/* $Id: cextspec.c,v 1.17 1997/01/26 14:30:17 cim Exp $ */

/* Copyright (C) 1994, 1998 Sverre Hvammen Johansen,
 * Department of Informatics, University of Oslo.
 *
 * 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; version 2.
 *
 * 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. */

/* Inn og utlesing av externe spesifikasjoner */

/* TBD: Innlesing av identifikatorer mm må gjøres mer robust. */

#include "const.h"
#include "dekl.h"
#include "filelist.h"
#include "newstr.h"
#include "cimcomp.h"
#include "extspec.h"
#include "name.h"

#if STDC_HEADERS || HAVE_STRING_H
#include <string.h>
#else
#include <strings.h>
#endif

#ifdef TIME_WITH_SYS_TIME
#include <sys/time.h>
#include <time.h>
#else
#ifdef HAVE_SYS_TIME_H
#include <sys/time.h>
#else
#include <time.h>
#endif
#endif

#ifdef STDC_HEADERS
#include <stdlib.h>
#else
double strtod ();
#endif

#include <obstack.h>
char *xmalloc();

#define obstack_chunk_alloc xmalloc
#define obstack_chunk_free free
static struct obstack os_extspec;
static char *first_object_allocated_ptr_extspec;

/* HUSK AT REKKEF\LGEN SKAL V[RE categ,type,kind 
 *
 * Filen starter alltid med <tidsmerke><LF>
 *
 * Deklarasjon av en klasse:
 *
 * <categ><type><kind><navn><blank><'!'<prefiks navn><blank> | '&'>
 * <fornest><blank><connest><blank><maxusedref><blank>
 * <maxusedtxt><blank><maxusedval><blank><blno><blank><ent>
 * <param.spec><virt. spec><hidden og protected spec><deklarasjoner><LF>
 *
 * Deklarasjon og spesifisering av prosedyre:
 *
 * <categ><type><kind><navn><blank><(if (type==TREF)<'!'qualnavn><blank>) |
 *                                 (if (categ==CCPROC)'^'<cnavn><blank>) | '&'>
 * <blno><blank><ent><param.spec><LF>
 *
 *
 * Spesifisering av vanlige parametere og deklarasjon av variable:
 *
 * <categ><type><kind><navn><blank><(if (type==TREF)<qualnavn><blank>)
 * else if(type==TLABEL)<ent>) else tom>
 * <(if (categ==CCONST)<value><blank>) | tom>
 *
 * Spesifisering av et array:
 *
 * <categ><type><kind><navn><blank><(if (type==TREF)<qualnavn><blank>) | tom>
 * <dim>
 *
 * Spesifisering av EXTERNAL klasse eller prosedyre
 *
 * <&><type><kind><navn><blank><tidsmerke><blank><filnavn><LF>
 *
 *
 * Alle filer slutter med en ekstra <LF> */

#define ENDOF_CLASS_PROC_FILE '\n'
#define START_NEW_EXTERNAL_SPEC '&'
#define PREFIKS_MARKER '!'
#define CPROC_MARKER '^'
#define NO_MARKER '$'
#define inchar(f) getc(f)
#define getval(f, i)  { int tmp;fscanf(f,"%d",&tmp);i=tmp;}
#define getconst(f, i)  { fscanf(f,"%ld",&i);}

/******************************************************************************
                                                              INITEXTSPEC    */
void extspec_init (void)
{
  obstack_init (&os_extspec);
  first_object_allocated_ptr_extspec= obstack_alloc (&os_extspec, 0);
}

void extspec_reinit (void)
{
  obstack_free (&os_extspec, first_object_allocated_ptr_extspec);
}

/******************************************************************************
                                                                  GETNAME    */

static char * getname (FILE *f)
{
  int c;
  char *s, *sx;
  for (c= getc (f); c !=EOF && c != '\n' && c!= ' '; c= getc (f))
    obstack_1grow (&os_extspec, c);

  obstack_1grow (&os_extspec, 0);
  s= obstack_finish (&os_extspec);
  sx= tag (s);
  obstack_free (&os_extspec, s);
  return sx;
}

/* fscanf leter frem til neste \n eller blank (eller til slutten) men lar 
 * \n eller blank bli igjen.                                              
 * Hvis \n er forste tegn n}r fscanf kalles s} kastes dette tegnet.Men    
 * getc kalles etter fscanf s} vil denne returnere med \n.Derfor m} dette 
 * tegnet leses av etter at hvert navn er lest inn
 * For å overføre filnavn id til deklarasjonslageret */

char *timestamp="";	/* Det globale tidsmerket */
char *directive_timestamp="";
struct stamp *first_stamp;

static char timestampchars[63] =
{'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l', 'm', 
 'n', 'o', 'p', 'q', 'r', 's', 't', 'u', 'v', 'w', 'x', 'y', 'z', 
 'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M', 
 'N', 'O', 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z', 
 '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', '_'};

/******************************************************************************
                                                          GETTIMESTAMP       */

void gettimestamp (void)
{
#if GET_TIME_OF_DAY
  struct timeval tp;
  struct timezone tzp;
#endif

  FILE *f;
  int t, th;

  if (strcmp (directive_timestamp, ""))
    timestamp= directive_timestamp;
  else if (option_reuse_timestamp && (f = searc_and_open_name_in_archlist 
				      (extcodename, TRUE)) != NULL)
    {
      if (option_verbose)
	fprintf (stderr, "Reading atr-file %s\n", extcodename);
      /* Leser identifikasjon , som alltid ligger f|rst p} filen */
      {
	char r_buff[12];
	r_buff[0] = '\0';
	fscanf (f, "%11s\n", r_buff);
	if (strcmp (r_buff, "/*Cim_atr*/"))
	  merror (5, extcodename);
      }

      timestamp= getname (f);
      fclose (f);
    }
  else
    {
#if GET_TIME_OF_DAY
      gettimeofday (&tp, &tzp);
      t = tp.tv_sec;
      th = tp.tv_usec;
#else
      t = time (NULL);
      th = 0;
#endif
      th /= 252;

      obstack_1grow (&os_extspec, timestampchars[th - th / 63 * 63]);
      th /= 63;
      obstack_1grow (&os_extspec, timestampchars[th - th / 63 * 63]);
      while (t != 0)
	{
	  obstack_1grow (&os_extspec, timestampchars[t - t / 63 * 63]);
	  t /= 63;
	}
      obstack_1grow (&os_extspec, 0);
      timestamp= obstack_finish (&os_extspec);
    }
}

/******************************************************************************
                                                 GENATRFILENAMEFROMID        */

static char *genatrfilenamefromid (char *ident)
{
  int i;
  char *s, *sx;
  obstack_grow (&os_extspec, ident, strlen (ident));
  obstack_grow0 (&os_extspec, ".atr", 4);
  s= obstack_finish (&os_extspec);

  for (i = strlen (s) - 5; i >= 0; i--)
    if (s[i] >= 'A' && s[i] <= 'Z')
      s[i] += 32;		/* LOWERCASE */
  sx= tag (s);
  obstack_free (&os_extspec, s);
  return sx;
}

/******************************************************************************
                                              GENATRFILENAMEFROMFILENAME     */

static char *genatrfilenamefromfilename (char *filename)
{
  char *s, *sx;
  int len = strlen (filename);
  
  if (len >=4 && !strcmp (&filename[len - 4], ".atr")) 
    return (tag (filename));
      
  if (len >=4 && !(strcmp (&filename[len - 4], ".sim")
                  && strcmp (&filename[len - 4], ".SIM")
                  && strcmp (&filename[len - 4], ".cim")
		   && strcmp (&filename[len - 4], ".CIM")))
    obstack_grow (&os_extspec, filename, len - 4);
  else
    obstack_grow (&os_extspec, filename, len);

  obstack_grow0 (&os_extspec, ".atr", 4);
  s= obstack_finish (&os_extspec);
  sx= tag (s);
  obstack_free (&os_extspec, s);
  return sx;
}

/******************************************************************************
                                                              EXTERNAL_IS_IN */

static char external_is_in (char *ident, char kind)
{
  decl_t *rd;
  block_t *rb;

  rb = cblock;

  for (rd = rb->parloc; rd != NULL; rd = rd->next)
    if (rd->ident == ident && rd->kind == kind)
      return (TRUE);

  return (FALSE);
}

/******************************************************************************
                                                                    NEXTDECL */

static char *lesinn (char *filename);

static nextdecl (FILE *f, char *filename, char *timestamp)
{
  char type, kind, categ;
  char tegn;
  char *ident;

  char codeclass=0;
  char *rtname=NULL;

  categ = getc (f);

  if (categ == (char) EOF)
    merror (5, filename);
  if (categ == ENDOF_CLASS_PROC_FILE)
    return (FALSE);
  else if (categ == START_NEW_EXTERNAL_SPEC)
    {
      char *local_timestamp;
      char *local_filename;
      type = getc (f);
      kind = getc (f);

      ident = getname (f);	/* Leser navnet */
      local_timestamp= getname (f); /* tidsmerket   */
      local_filename= getname (f);    /* filnavnet    */

      if (!external_is_in (ident, kind))
	{
	  if (local_timestamp != lesinn (local_filename))
	    merror (4, filename);
	}
      return (TRUE);
    }

  type = getc (f);
  kind = getc (f);
  ident = getname (f);

  switch (kind)
    {
    case KPROC:
    case KCLASS:
      tegn = getc (f);
      if (tegn == PREFIKS_MARKER)
	{
	  prefquantident = getname (f);
	  tegn = getc (f);
	  if (tegn == CPROC_MARKER)
	    {
	      rtname = getname (f);
	      if (categ != CCPROC)
		codeclass = getc (f) - '0';
	      else
		codeclass = CCCPROC;
	    }
	  else
	    ungetc (tegn, f);
	}
      else
	{
	  prefquantident = 0;
	  if (tegn == CPROC_MARKER)
	    {
	      rtname = getname (f);
	      if (categ != CCPROC)
		codeclass = getc (f) - '0';
	      else
		codeclass = CCCPROC;
	    }
	}
      reg_decl (ident, type, kind, categ);
      begin_block (kind);

      cblock->timestamp= timestamp;
      cblock->filename= filename;

      if (kind == KCLASS)
	{
	  getval (f, cblock->fornest);
	  getval (f, cblock->connest);
#if ACSTACK_IN_OBJ
	  getval (f, cblock->maxusedref);
	  getval (f, cblock->maxusedtxt);
	  getval (f, cblock->maxusedval);
#endif
	}
      getval (f, cblock->ptypno);
      if (getc (f) == '%')
        cblock->blno = cblock->ptypno;
      getval (f, cblock->ent);
      /* Les inn parametere, virtuelle, hidden, protected og deklarasjoner */
      while (nextdecl (f, filename, timestamp));
      end_block (rtname, codeclass);
      break;
    default:
      if (type == TREF)
	{
	  prefquantident = getname (f);
	}
      switch (categ)
	{
	case CCONST:
	  reg_decl (ident, type, kind, categ);
	  if (type == TTEXT)
	    {
	      int i;
	      getval (f, i);
	      getc (f);
	      cblock->lastparloc->value.tval.txt= getname (f);
	    }
	  else if (type == TREAL)
	    {
	      char *s;
	      s= getname (f);
	      cblock->lastparloc->value.rval= strtod (s, NULL);
	    }
	  else
	    {
	      getconst (f, cblock->lastparloc->value.ival);
	      getc (f);
	    }
	  break;
	default:
	  reg_decl (ident, type, kind, categ);
	  if (type == TLABEL)
	    getconst (f, cprevdecl->plev);
	  break;
	}
      if (kind == KARRAY)
	getval (f, cblock->lastparloc->dim);
    }
  return (TRUE);
}

/******************************************************************************
                                                                      LESINN */

static char *lesinn (char *filename)
{
  struct stamp *st;
  char *timestamp;
  FILE *f;

  f = searc_and_open_name_in_archlist (filename, TRUE);
  if (f == NULL) return (NULL);

  if (option_verbose)
    fprintf (stderr, "Reading atr-file %s\n", filename);
  /* Leser identifikasjon , som alltid ligger f|rst p} filen */
  {
    char r_buff[12];
    r_buff[0] = '\0';
    fscanf (f, "%11s\n", r_buff);	
    if (strcmp (r_buff, "/*Cim_atr*/"))
      merror (5, filename);
  }

  /* Leser tidsmerke */

  timestamp= getname (f); 

  for (st = first_stamp; st != NULL; st = st->next)
    if (st->timestamp == timestamp)
      goto found;
  st = (struct stamp *) obstack_alloc (&os_extspec, sizeof (struct stamp));
  st->timestamp = timestamp;
  st->next = first_stamp;
  st->lest_inn = FALSE;
  st->filename = filename;
  first_stamp = st;
found:
  if (st->filename != filename)
    merror (11, filename);
  st->lest_inn = TRUE;
  /* Leser inn liste med tidsmerker */
  while (getc (f) == ' ')
    {
      char *local_timestamp= getname (f);
      char *local_filename= getname (f);

      for (st = first_stamp; st != NULL; st = st->next)
	if (st->timestamp == local_timestamp)
	  goto find_next;
      st = (struct stamp *) obstack_alloc (&os_extspec, sizeof (struct stamp));
      st->timestamp = local_timestamp;
      st->next = first_stamp;
      st->lest_inn = FALSE;
      st->filename = local_filename;
      first_stamp = st;
    find_next:;
      if (st->filename != local_filename)
	merror (11, local_filename);
    }

  while (nextdecl (f, filename, timestamp));

  fclose (f);
  return (timestamp);
}

/******************************************************************************
                                                        LESINN_EXTERNAL_SPEC */

void lesinn_external_spec (char *ident, char *filename, char kind)
{
  char *hprefquantident;
  block_t *hcblock;
  decl_t *hclastdecl,
   *rd;
  hprefquantident = prefquantident;
  hcblock = cblock;
  hclastdecl = cblock->lastparloc;
  if (filename == NULL)
    filename = genatrfilenamefromid (ident);
  else
    filename = genatrfilenamefromfilename (filename);
  if (!external_is_in (ident, kind))
    {
      if (lesinn (filename) == NULL)
	{
	  merror (3, filename);
	  return;
	}
    }

  /* Denne modulen skal ha categ=CEXTRMAIN */
  if (hclastdecl == NULL)
    rd = hcblock->parloc;
  else
    rd = hclastdecl;
  for (; rd != NULL && rd->ident != ident; rd = rd->next);

  if (rd != NULL)
    rd->categ = CEXTRMAIN;

  prefquantident = hprefquantident;
}

static char link;

/******************************************************************************
                                                           WRITE_INDENTATION */
static void write_indentation (FILE *f, int level)
{
  int i;
  fprintf (f, "\n");
  for (i=1; i<=level; i++) fprintf (f, "   ");
}

/******************************************************************************
                                                              WRITE_CHAR_MIF */
static void write_char_mif (FILE *f, unsigned char c)
{
  if ((isprint (c)
#if ISO_LATIN
       || c >= 160
#endif
       ) && c != '!' && c != '"')
    fprintf (f, "= '%c'", c);
  else
    fprintf (f, "= '!%d!'", c);
}

/******************************************************************************
                                                              WRITE_TEXT_MIF */
static void write_text_mif (FILE *f, unsigned char *s)
{
  int i;
  fprintf (f, "= \"");
  for (i = 0; s[i]; i++)
    if (s[i] == '\\')
      {
	char j = 0;
	j = j * 8 + s[++i] - '0';
	j = j * 8 + s[++i] - '0';
	j = j * 8 + s[++i] - '0';
	if (j == ' ')
	  putc (' ', f);
	else
	  fprintf (f, "!%d!", j);
      }
  else
    putc (s[i], f);
  putc ('"', f);
}

/******************************************************************************
                                                              WRITE_DECL_MIF */

static write_decl_mif (FILE *f, decl_t *rd, int level)
{
  if (rd->kind == KBLOKK || rd->kind == KPRBLK || rd->kind == KFOR || 
      rd->kind == KINSP) return;
  if (level == 0)
    {
      int i;
      fprintf (f, "\n\n%% **************************************"
	       "************************************* %%\n%% ");
      for (i= 75-strlen(rd->ident); i>0; i--)fprintf (f, " ");
      fprintf (f, "%s %%", rd->ident);
    }
  write_indentation (f, level);
  switch(rd->categ)
    {
    case CVALUE:
      fprintf (f, "value: ");
      break;
    case CNAME:
      fprintf (f, "name: ");
      break;
    case CVAR:
      fprintf (f, "var: ");
      break;
    case CEXTR:
      break;
    case CEXTRMAIN:
      break;
    case CEXTROUT:
      break;
    case CHIDEN:
      fprintf (f, "hidden ");
      break;
    case CPROT:
      fprintf (f, "protected ");
      break;
    case CHIPRO:
      fprintf (f, "hidden proteced ");
      break;
    case CCPROC:
      fprintf (f, "external C procedure %s is "
		      ,rd->descr->rtname);
      break;

    }
  switch(rd->type)
    {
    case TINTG:
      fprintf (f, "integer ");
      break;
    case TREAL:
      fprintf (f, "real ");
      break;
      break;
    case TBOOL:
      fprintf (f, "boolean ");
      break;
    case TCHAR:
      fprintf (f, "character ");
      break;
    case TLABEL:
      if (rd->kind == KARRAY) fprintf (f, "switch ");
      else if (rd->categ != CLOCAL) fprintf (f, "label ");
      break;
    case TTEXT:
      fprintf (f, "text ");
      break;
    case TREF:
      fprintf (f, "ref (%s) ", rd->prefqual->ident);
      break;
    case TERROR:
      break;
    case TVARARGS:
      break;
    }
  switch(rd->kind)
    {
    case KARRAY:
      if (rd->type != TLABEL) fprintf (f, "array ");
      break;
    case KPROC:
      fprintf (f, "procedure ");
      break;
    case KCLASS:
      if (rd->prefqual != NULL && rd->prefqual != commonprefiks)
	/* Prefiks klassens navn eller kvalifikasjon */
	fprintf (f, "%s ", rd->prefqual->ident);
      fprintf (f, "class ");
      break;
    }

  fprintf (f, "%s", rd->ident);

  if (rd->categ == CEXTR || rd->categ == CEXTRMAIN)
    {
    fprintf (f, "= \"%s %s\"", rd->descr->timestamp, rd->descr->filename);
    }
  else if (rd->kind == KPROC || rd->kind == KCLASS)
    {
      decl_t *rdv;
      block_t *rb;
      decl_t *rdx;
      rb = rd->descr;
      if (rd->categ == CEXTROUT)
	rd->categ = CEXTR;
	  
      /* evt. parametere */
      fprintf (f, " (");
      for (rdx = rb->parloc; rdx != NULL && (rdx->categ == CDEFLT || rdx->categ == CNAME ||
				   rdx->categ == CVAR || rdx->categ == CVALUE)
	   ; rdx = rdx->next)
	write_decl_mif (f, rdx, level+1);

      fprintf (f, ")");

      switch (rd->categ)
	{
	case CDEFLT:
	case CNAME:
	case CVAR:
	case CVALUE:
	case CVIRT:
	  break;
	default:
	  fprintf (f, ";");
	}

#if 0
      /* Fornest,Connest,blno,ent */
      if (rb->quant.kind == KCLASS)
	{
	  fprintf (f, "\n%% f_c_b_e %d %d ", rb->fornest, rb->connest);
#if ACSTACK_IN_OBJ
	  fprintf (f, "%d %d %d ", rb->fornest, rb->connest, rb->maxusedret);
#endif
	  fprintf (f, "%d %d", rb->blno, rb->ent);
	}
#endif

      if (rb->quant.kind == KCLASS)
	{
	  int i;
	  write_indentation (f, level);
	  fprintf (f, "virtual:");
	  /* evt. virtuelle spesifiksajoner , men bare de som er spesifisert */
	  /* i denne klassen. Ikke de akkumulerte. De akkumuleres opp av     */
	  /* sjekkdekl senere                                                */
	  i = (rb->quant.plev > 0) ? rb->quant.prefqual->descr->navirt
	    + rb->quant.prefqual->descr->navirtlab : 0;
	  for (rdv = rb->virt; i-- > 0; rdv = rdv->next);
	  for (; rdv != NULL; rdv = rdv->next)
	    write_decl_mif (f, rdv, level+1);

	  /* evt. spesifikasjoner av hidden og protected. */
	  for (rdv = rb->hiprot; rdv != NULL; rdv = rdv->next)
	    write_decl_mif (f, rdv, level+1);

          write_indentation (f, level);
          fprintf (f, "begin");
	  /* Lokale deklarasjoner NB Forutsetter at rdx peker p} forste
	   * deklarasjon */
	  for (; rdx != NULL; rdx = rdx->next)
	    write_decl_mif (f, rdx, level+1);
	  write_indentation (f, level);
	  fprintf (f, "end");
	}
    }
  else
    {
#if 0
      if (rd->type == TLABEL)
	fprintf (f, "\n%% ENT %d", rd->plev);
#endif
      if (rd->categ == CCONST)
	if (rd->type == TTEXT)
	  write_text_mif (f, rd->value.tval.txt);
	else if (rd->type == TREAL)
	  {
	    char s[100];
	    int i;
	    sprintf (s, "= %.16le", rd->value.rval);
	    for (i=0; s[i]; i++) 
	      if (s[i]=='e') 
		{
		  s[i]='&';
		  break;
		}
	    fprintf (f, "%s", s);
	  }
	else if (rd->type == TCHAR)
	  write_char_mif (f, rd->value.ival);
	else
	  fprintf (f, "= %ld", rd->value.ival);
      if (rd->kind == KARRAY && rd->type != TLABEL)
	{
	  int i;
	  fprintf (f, "( ");
	  for (i=2; i<= rd->dim; i++) fprintf (f, ", ");
	  fprintf (f, ")");
	}
    }

  switch (rd->categ)
    {
    case CDEFLT:
    case CNAME:
    case CVAR:
    case CVALUE:
      if (rd->next!=NULL && (rd->next->categ == CDEFLT || 
			     rd->next->categ == CNAME ||
			     rd->next->categ == CVAR || 
			     rd->next->categ == CVALUE))
	fprintf(f, ", ");
      break;
    case CLOCAL:
      if (rd->type == TLABEL && rd->kind == KSIMPLE) 
	{
	  fprintf (f, ":");
	  break;
	}
    default:
      fprintf (f, ";");
    }
}

/******************************************************************************
                                                               WRITE_ALL_MIF */

static void write_all_mif (void)
{
  /* Trenger ikke skrive ut lokale deklarasjoner i procedyrer */

  decl_t *rd;
  struct stamp *st;
  FILE *f;

  char hcateg;

  if ((f = fopen (mifcodename, "w")) == NULL)
    merror (9, mifcodename);

  /* Skriver f|rst ut identifikasjon til find */
  fprintf (f, "%% Cim_mif");

#if 0
  /* Skriver ut tidsmerke */
  fprintf (f, "\n%%timestamp %s", timestamp);

  /* Skriver ut tidsmerke til alle moduler */
  for (st = first_stamp; st != NULL; st = st->next)
    fprintf (f, "\n%% timestamp_other_module %s %s"
		    ,st->timestamp, st->filename);
#endif

  for (rd = sblock->parloc; rd != NULL; rd = rd->next)
    if (rd->categ == CEXTR) /* OK */ ;
    else 
      if (rd->categ == CEXTRMAIN)
      {
	rd->categ = CEXTR;
	write_decl_mif (f, rd, 0);
      }
    else
      {
	hcateg = rd->categ;
	if (rd->categ != CCPROC) rd->categ = CEXTROUT;
	if (rd->kind == KCLASS || rd->kind == KPROC)
	  write_decl_mif (f, rd, 0);
	rd->categ = hcateg;
      }
  fprintf (f, "\n\n%%eof\n");
  fclose (f);
}

/******************************************************************************
                                                              WRITE_DECL_EXT */

static write_decl_ext (FILE *f, decl_t *rd)
{
  if (rd->kind == KBLOKK || rd->kind == KPRBLK || rd->kind == KFOR || 
      rd->kind == KINSP) ;
  else if (rd->categ == CEXTR || rd->categ == CEXTRMAIN)
    fprintf (f, "&%c%c%s %s %s\n", rd->type, rd->kind
		    ,rd->ident, rd->descr->timestamp, rd->descr->filename);
  else if (rd->kind == KPROC || rd->kind == KCLASS)
    {
      decl_t *rdv;
      block_t *rb;
      rb = rd->descr;
      if (rd->categ == CEXTROUT)
	rd->categ = CEXTR;
      /* Skriver ut <categ><type><kind><navn><blank> */
      fprintf (f, "%c%c%c%s ", rd->categ, rd->type, rd->kind,
		      rd->ident);

      if (rd->prefqual != NULL && rd->prefqual != commonprefiks)
	/* Prefiks klassens navn eller kvalifikasjon */
	fprintf (f, "%c%s ", PREFIKS_MARKER, rd->prefqual->ident);
      else if (rd->categ == CCPROC)	/* C-navnet */
	fprintf (f, "%c%s ", CPROC_MARKER
			,rd->descr->rtname);
      else
	fprintf (f, "%c", NO_MARKER);

      /* Fornest,Connest,blno,ent */
      if (rb->quant.kind == KCLASS)
	{
	  fprintf (f, "%d %d ", rb->fornest, rb->connest);
#if ACSTACK_IN_OBJ
	  fprintf (f, "%d %d %d ", rb->fornest, rb->connest, rb->maxusedref);
#endif
	}
      fprintf (f, "%d %d", rb->blno, rb->ent);

      /* evt. parametere */
      for (rd = rb->parloc; rd != NULL && (rd->categ == CDEFLT || rd->categ == CNAME ||
				   rd->categ == CVAR || rd->categ == CVALUE)
	   ; rd = rd->next)
	write_decl_ext (f, rd);

      if (rb->quant.kind == KCLASS)
	{
	  int i;
	  /* evt. virtuelle spesifiksajoner , men bare de som er spesifisert */
	  /* i denne klassen. Ikke de akkumulerte. De akkumuleres opp av     */
	  /* sjekkdekl senere                                                */
	  i = (rb->quant.plev > 0) ? rb->quant.prefqual->descr->navirt
	    + rb->quant.prefqual->descr->navirtlab : 0;
	  for (rdv = rb->virt; i-- > 0; rdv = rdv->next);
	  for (; rdv != NULL; rdv = rdv->next)
	    write_decl_ext (f, rdv);

	  /* evt. spesifikasjoner av hidden og protected. */
	  for (rdv = rb->hiprot; rdv != NULL; rdv = rdv->next)
	    write_decl_ext (f, rdv);

	  /* Lokale deklarasjoner.  NB Forutsetter at rd peker p} forste
	   * deklarasjon */
	  for (; rd != NULL; rd = rd->next)
	    write_decl_ext (f, rd);
	}
      fprintf (f, "%c", ENDOF_CLASS_PROC_FILE);
    }
  else
    {
      fprintf (f, "%c%c%c%s ", rd->categ, rd->type,
		      rd->kind, rd->ident);

      if (rd->type == TREF)
	fprintf (f, "%s ", rd->prefqual->ident);
      else if (rd->type == TLABEL)
	fprintf (f, "%ld", rd->plev);

      if (rd->categ == CCONST)
	if (rd->type == TTEXT)
	  fprintf (f, "%ld %s "
			  ,strlen (rd->value.tval.txt)
			  ,rd->value.tval.txt);
	else if (rd->type == TREAL)
	  fprintf (f, "%.16e ", rd->value.rval);
	else
	  fprintf (f, "%ld ", rd->value.ival);
      if (rd->kind == KARRAY)
	fprintf (f, "%c", (rd->dim + ((short) '0')));
    }
}

/******************************************************************************
                                                               WRITE_ALL_EXT */

void write_all_ext (void)
{
  /* Trenger ikke skrive ut lokale deklarasjoner i procedyrer */

  decl_t *rd;
  struct stamp *st;
  FILE *f;

  char hcateg;

#if OPEN_FILE_IN_BINARY_MODE
  if ((f = fopen (extcodename, "wb")) == NULL)
#else
  if ((f = fopen (extcodename, "w")) == NULL)
#endif
    merror (9, extcodename);

  /* Skriver f|rst ut identifikasjon til find */
  fprintf (f, "/*Cim_atr*/\n");

  /* Skriver ut tidsmerke */
  fprintf (f, "%s\n", timestamp);

  /* Skriver ut tidsmerke til alle moduler */
  for (st = first_stamp; st != NULL; st = st->next)
    fprintf (f, " %s %s\n"
		    ,st->timestamp, st->filename);
  fprintf (f, "\n");
  for (rd = sblock->parloc; rd != NULL; rd = rd->next)
    if (rd->categ == CEXTR) /* OK */ ;
    else if (rd->categ == CEXTRMAIN)
      {
	rd->categ = CEXTR;
	write_decl_ext (f, rd);
      }
    else
      {
	hcateg = rd->categ;
	if (rd->categ != CCPROC) rd->categ = CEXTROUT;
	if (rd->kind == KCLASS || rd->kind == KPROC)
	  write_decl_ext (f, rd);
	rd->categ = hcateg;
      }
  fprintf (f, "%c", ENDOF_CLASS_PROC_FILE);
  fclose (f);

  if (option_write_mif) write_all_mif();
}

/******************************************************************************
                                                                MORE_MODULES */

void more_modules (void)
{
  FILE *f;
  struct stamp *st;
  char *local_timestamp;
  for (st = first_stamp; st != NULL; st = st->next)
    if (st->lest_inn == FALSE && (f = fopen (st->filename,
#if OPEN_FILE_IN_BINARY_MODE
					     "rb"
#else
					     "r"
#endif
					     )) != NULL)
      {
	char *newlink_moduler;
	char r_buff[12];
	
	/* Leser identifikasjon , som alltid ligger f|rst p} filen */
	r_buff[0] = '\0';
	fscanf (f, "%11s\n", r_buff);
	if (strcmp (r_buff, "/*Cim_atr*/"))
	  merror (5, st->filename);
	
	/* Leser tidsmerke */

	local_timestamp= getname (f);
	if (local_timestamp == st->timestamp)
	  {
	    if (option_verbose)
	      fprintf (stderr, "Reading atr-file %s\n", st->filename);
	    insert_name_in_linklist 
	      (transform_name (st->filename, ".atr", ".o"), TRUE);
	      
	  }
      }
}
