/* glplan4.c (l_misc) */

/*----------------------------------------------------------------------
-- Copyright (C) 2000, 2001, 2002 Andrew Makhorin <mao@mai2.rcnet.ru>,
--               Department for Applied Informatics, Moscow Aviation
--               Institute, Moscow, Russia. All rights reserved.
--
-- This file is a part of GLPK (GNU Linear Programming Kit).
--
-- GLPK 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, or (at your option)
-- any later version.
--
-- GLPK 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 GLPK; see the file COPYING. If not, write to the Free
-- Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
-- 02111-1307, USA.
----------------------------------------------------------------------*/

#include <stdarg.h>
#include <stdio.h>
#include <string.h>
#include "glplang.h"

#define error print

/*----------------------------------------------------------------------
-- initialize - initialize the language processor environment.
--
-- This routine initializes the language processor environment. The
-- character string fname specifies an input text file which contains
-- a model description.
--
-- If initialization is successful, the routine returns zero. Otherwise
-- the routine returns non-zero. */

PDB *pdb = NULL;

int initialize(char *fname)
{     insist(pdb == NULL);
      pdb = umalloc(sizeof(PDB));
      pdb->text = open_text(fname);
      if (pdb->text == NULL)
      {  ufree(pdb);
         pdb = NULL;
         return 1;
      }
      pdb->flag = 0;
      pdb->spar_pool = create_pool(sizeof(SPAR));
      pdb->item_pool = create_pool(sizeof(ITEM));
      pdb->memb_pool = create_pool(sizeof(MEMB));
      pdb->expr_pool = create_pool(sizeof(EXPR));
      pdb->code_pool = create_pool(sizeof(CODE));
      pdb->var_pool = create_pool(sizeof(VAR));
      pdb->cons_pool = create_pool(sizeof(CONS));
      pdb->tree = create_avl((int (*)(void *, void *))strcmp);
      strcpy(pdb->model_name, "unknown");
      pdb->obj_dir = '-';
      pdb->obj_spar = NULL;
      pdb->obj_memb = NULL;
      pdb->index = NULL;
      pdb->array = NULL;
      return 0;
}

/*----------------------------------------------------------------------
-- terminate - terminate the language processor environment.
--
-- This routine terminates the language processor environment freeing
-- all the memory allocated to working data structures. */

void terminate(void)
{     insist(pdb != NULL);
      close_text(pdb->text);
      delete_pool(pdb->spar_pool);
      delete_pool(pdb->item_pool);
      delete_pool(pdb->memb_pool);
      delete_pool(pdb->expr_pool);
      delete_pool(pdb->code_pool);
      delete_pool(pdb->var_pool);
      delete_pool(pdb->cons_pool);
      delete_avl(pdb->tree);
      if (pdb->index != NULL) delete_avl(pdb->index);
      ufree(pdb);
      pdb = NULL;
      return;
}

/*----------------------------------------------------------------------
-- fatal - print error message and terminate processing.
--
-- This routine prints an error message (using the error routine) and
-- performs non-local goto to terminate processing. */

void fatal(char *fmt, ...)
{     va_list arg;
      char msg[4095+1];
      va_start(arg, fmt);
      vsprintf(msg, fmt, arg);
      insist(strlen(msg) <= 4095);
      va_end(arg);
      error("%s:%d: %s", pdb->text->file, pdb->text->line, msg);
      if (pdb->flag) longjmp(pdb->jump, 1);
      fault("fatal: exit address not set");
      /* no return */
}

/*----------------------------------------------------------------------
-- get_token - scan the next token.
--
-- This routine scans the next token from the input text stream (using
-- the scan_token routine). The routine also recognizes some additional
-- multi-character tokens. */

void get_token(void)
{     scan_token(pdb->text);
      if (pdb->text->err > 0)
      {  if (pdb->flag) longjmp(pdb->jump, 1);
         fault("get_token: exit address not set");
      }
      if (token == T_NAME)
      {  if (strlen(image) > MAX_NAME)
            fatal("symbolic name `%.*s...' too long", MAX_NAME, image);
      }
      else if (t_spec("+") && pdb->text->c == '+')
      {  scan_token(pdb->text);
         strcpy(image, "++");
      }
      else if (t_spec("-") && pdb->text->c == '-')
      {  scan_token(pdb->text);
         strcpy(image, "--");
      }
      else if (t_spec(">") && pdb->text->c == '=')
      {  scan_token(pdb->text);
         strcpy(image, ">=");
      }
      else if (t_spec("<") && pdb->text->c == '=')
      {  scan_token(pdb->text);
         strcpy(image, "<=");
      }
      else if (t_spec("!") && pdb->text->c == '=')
      {  scan_token(pdb->text);
         strcpy(image, "!=");
      }
      else if (t_spec(":") && pdb->text->c == '=')
      {  scan_token(pdb->text);
         strcpy(image, ":=");
      }
      return;
}

/*----------------------------------------------------------------------
-- find_mute - find mute letter.
--
-- This routine finds mute letter i in the list of mute letters mute
-- of the length dim and returns a position of the mute letter found.
-- If the letter i is missing, the routine returns negative value. */

int find_mute(int dim, int mute[], int i)
{     int k;
      for (k = 0; k < dim; k++) if (mute[k] == i) return k;
      return -1;
}

/*----------------------------------------------------------------------
-- create_index - create array index.
--
-- This routine creates an index for the given array spar (in order to
-- search for array members for logarithmic time).
--
-- Note that only one array may be indexed at the same time. */

void create_index(SPAR *spar)
{     insist(pdb->index == NULL);
      pdb->index = create_avl((int (*)(void *, void *))cmp_tuples);
      pdb->array = spar;
      return;
}

/*----------------------------------------------------------------------
-- cmp_tuples - compare tuples.
--
-- This routine is auxiliary. It is used by array indexing routines for
-- comparing two tuples. */

int cmp_tuples(ITEM *item1[MAX_DIM], ITEM *item2[MAX_DIM])
{     int k;
      for (k = 0; k < pdb->array->dim; k++)
      {  if (item1[k] < item2[k]) return -1;
         if (item1[k] > item2[k]) return +1;
      }
      return 0;
}

/*----------------------------------------------------------------------
-- find_memb - find array member.
--
-- This routine searches for member of the current indexed array which
-- has the given tuple specified by the parameter item.
--
-- If the member has been found, the routine returns a pointer to this
-- member. Otherwise the routine returns NULL. */

MEMB *find_memb(ITEM *item[MAX_DIM])
{     AVLNODE *node;
      insist(pdb->index != NULL);
      node = find_by_key(pdb->index, item);
      return node == NULL ? NULL : (MEMB *)node->link;
}

/*----------------------------------------------------------------------
-- index_memb - index array member.
--
-- This routine enters the specified member memb of the current indexed
-- array to the array index. This operation assumes that the member has
-- been added to the corresponding array. */

void index_memb(MEMB *memb)
{     AVLNODE *node;
      insist(pdb->index != NULL);
      node = insert_by_key(pdb->index, memb->item);
      node->link = memb;
      return;
}

/*----------------------------------------------------------------------
-- delete_index - delete array index.
--
-- This routine deletes the current array index which was previously
-- created by the create_index routine. */

void delete_index(void)
{     insist(pdb->index != NULL);
      delete_avl(pdb->index);
      pdb->index = NULL;
      pdb->array = NULL;
      return;
}

/*----------------------------------------------------------------------
-- outstr - wrapped buffered printing.
--
-- This routine buffers and prints the character string str using the
-- print routine. */

void outstr(char *str)
{     static char outbuf[255+1];
      if (str == NULL)
         strcpy(outbuf, "");
      else if (strcmp(str, "\n") == 0)
      {  print("%s", outbuf);
         strcpy(outbuf, "");
      }
      else
      {  if (strlen(outbuf) + strlen(str) > 72)
         {  print("%s", outbuf);
            strcpy(outbuf, "   ");
         }
         strcat(outbuf, str);
      }
      return;
}

/*----------------------------------------------------------------------
-- load_model - load math programming model description.
--
-- This routine loads a description of math programming model written
-- in the modeling language GLPK/L. */

void load_model(void)
{     insist(pdb != NULL);
      print("load_model: reading model from `%s'...", pdb->text->file);
      /* get the very first token */
      get_token(/* _|_ */);
      /* parse model description */
      parse_model();
      print("load_model: model `%s'", pdb->model_name);
      print("load_model: %d lines were read", pdb->text->line);
      return;
}

/* eof */
