/*******************************************************************************
*
* McStas, neutron ray-tracing package
*         Copyright 1997-2002, All rights reserved
*         Risoe National Laboratory, Roskilde, Denmark
*         Institut Laue Langevin, Grenoble, France
*
* Kernel: cogen.c
*
* %Identification
* Written by: K.N.
* Date: Aug  20, 1997
* Origin: Risoe
* Release: McStas 1.6
* Version: 1.24
*
* Code generation from instrument definition.
*
* $Log: cogen.c,v $
* Revision 1.58  2005/11/02 09:18:38  farhi
* More tolerant about DEFINITION parameter values, enabling table init as for PowderN
*
* Revision 1.57  2005/09/15 10:46:10  farhi
* Added mccompcurtype to be e.g. the component type/class being used.
* Not used yet, but will be with NeXus support and probably elsewere
*
* Revision 1.56  2005/07/27 11:29:41  farhi
* missing arg in printf
*
* Revision 1.55  2005/07/18 14:43:05  farhi
* Now gives a warning message per component for 'computational absorbs'
*
* Revision 1.54  2005/07/06 08:24:43  farhi
* Moved again SHAREd blocks at the very begining of instrument C code
* so that no name clash can occur.
*
* Revision 1.53  2005/07/05 12:18:00  farhi
* Moved SHAREs defore definition/setting parameter comp definition
* to avoid name clash. Was reason for failure of updated read_table-lib
*
* Revision 1.52  2005/06/20 13:32:45  farhi
* Only display mcstas-r.* embed files with --verbose
*
* Revision 1.51  2005/06/20 09:16:48  farhi
* Corrected mcScattered definition (char -> MCNUM)
*
* Revision 1.50  2005/06/20 09:02:10  farhi
* Some more info in mcstas --verbose mode.
*
* Revision 1.49  2005/06/20 08:01:58  farhi
* Install ABSORB counter for run-time PROP macros.
* Report at end of simulation if needed.
*
* Revision 1.48  2005/05/31 13:26:16  farhi
* Make possible to change setting parameter values in the INITIALIZE section.
* It is thus easier to auto-configure components in their INIT code, depending
* on some tests and checks...
* Other sections use local copies of the setting parameters, e.g. TRACE, EXTEND
* FINALLY, SAVE, ...
*
* Revision 1.47  2005/02/17 15:51:02  farhi
* Added a neutron event per component, so that amessage is displayed when
* no neutron reaches the COMP in FINALLY. Requested by R. Cubitt
*
* Revision 1.46  2004/11/30 16:09:56  farhi
* Uses SIG_MESSAGE macro defined as strcpy(mcsigmessage...) when signals are used
* or ignored when NOSIGNALS
*
* Revision 1.45  2004/11/29 14:30:52  farhi
* Defines a component name as instrument name for usage of mcstas-r functions
* and macros in FINALLY and SAVE (e.g. DETECTOR_OUT...)
*
* Revision 1.44  2004/09/10 15:09:56  farhi
* Use same macro symbols for mcstas kernel and run-time for code uniformity
*
* Revision 1.43  2004/09/03 13:43:29  farhi
* Removed duplicated Instr:FINALLY code (in SAVE and FINALLY). May cause SEGV.
*
* Revision 1.42  2003/10/06 14:59:14  farhi
* Also insert component index in automatic source comments
*
* Revision 1.41  2003/09/05 08:59:05  farhi
* added INSTRUMENT parameter default value grammar
* mcinputtable now has also default values
* mcreadpar now uses default values if parameter not given
* extended instr_formal parameter struct
* extended mcinputtable structure type
*
* Revision 1.40  2003/08/12 13:32:25  farhi
* Add generation date/time in C code header
*
* Revision 1.39  2003/02/11 12:28:45  farhi
* Variouxs bug fixes after tests in the lib directory
* mcstas_r  : disable output with --no-out.. flag. Fix 1D McStas output
* read_table:corrected MC_SYS_DIR -> MCSTAS define
* monitor_nd-lib: fix Log(signal) log(coord)
* HOPG.trm: reduce 4000 points -> 400 which is enough and faster to resample
* Progress_bar: precent -> percent parameter
* CS: ----------------------------------------------------------------------
*
* Revision 1.24 2002/09/17 10:34:45 ef
* added comp setting parameter types
*
* $Id: cogen.c,v 1.58 2005/11/02 09:18:38 farhi Exp $
*
*******************************************************************************/

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


/*******************************************************************************
* Some general comments on code generation.
*
* Code is output in the form of strings using the following functions:
*   cout();                        (one line at a time)
*   coutf();                       (with printf-style formatting)
*
* The type of numbers used in the generated code is given by the macro MCNUM
* (defined in mcstas-r.h).
*
* All generated identifiers are prefixed with the string ID_PRE, to make name
* clashes less likely to occur. Currently, for simplicity, we output modified
* names directly, eg.
*
*   cout("void " ID_PRE "init(void);");
*
* But to make a later transition to a better name generation scheme possible,
* it is important to use the ID_PRE macro everywhere identifiers are
* generated.
*
* After the ID_PRE prefix a few letters occur in generated names to
* distinguish different kinds of identifiers (instrument parameters,
* component definition parameters, internal temporary variables and so on).
* Care must be takes to choose these letters such that no name clashes will
* occur with names generated by other parts of the code or generated from
* user symbols.
*
* Finally, names generated from user symbols are generally chosen to match
* the originals as closely as possible to make the generated code more
* readable (for debugging purposes).
*
* The following is a list of the identifiers generated in the output. The
* ID_PRE prefix is denoted by ##. The first column gives the identifier as it
* appears in the generated code, the second explains the origin of the
* identifier in the instrument definition source (if any).
*
* ##ip<PAR>        From instrument parameter <PAR>.
* ##init           Function containing initialization code.
* ##inputtable     Table of instrument parameters.
* ##NUMIPAR        Macro giving the number of instrument parameters.
* ##numipar        Global variable with the value of ##NUMIPAR.
* ##c<C>_<P>       From definition or setting parameter <P> in component
*                  instance <C>.
* ##posa<COMP>     Absolute position of coordinate system of <COMP>.
* ##posr<COMP>     Position of <COMP> relative to previous component.
* ##rota<COMP>     Absolute rotation.
* ##rotr<COMP>     Relative rotation.
* ##tc1            Temporary variable used to compute transformations.
* ##tc2
* ##tr1
* ##nx             Neutron state (position, velocity, time, and spin).
* ##ny
* ##nz
* ##nvx
* ##nvy
* ##nvz
* ##nt
* ##nsx
* ##nsy
* ##nsz
* ##np
* ##compcurname
* ##compcurtype
* ##compcurindex
* ##absorb          label for ABSORB (goto)
* ##Scattered       Incremented each time a SCATTER is done
* ##NCounter        Incremented each time a neutron is entering the component
* ##AbsorbProp      single counter for removed events in PROP calls
* ##comp_storein    Positions of neutron entering each comp (loc. coords)
* ##Group<GROUP>    Flag true when in an active group
* ##sig_message     Message for the signal handler (debug/trace, sim status)
*******************************************************************************/



/*******************************************************************************
* Generation of declarations.
*
* The following declarations are generated (## denotes the value ID_PRE):
* 1. Header file #include - "mcstas-r.h" for declarations for the
*    mcstas runtime.
* 2. Declarations of global variables to hold the values of the instrument
*    parameters. For example, for an instrument parameter OMM, the
*    declaration "MCNUM ##ipOMM;" is generated.
* 3. Declaration of a table ##inputtable containing the list of instrument
*    parameters. For each parameter, the name, a pointer to the
*    corresponding global variable, and the type (double, int,
*    string) is given. The macro ##NUMIPAR gives the number of
*    entries in the table and is also found as the value of the
*    variable ##numipar; in addition, the table is terminated by two
*    NULLs. This table is used to read the instrument parameters from
*    the user or from another program such as TASCOM.
* 4. User declarations copied verbatim from the instrument definition file.
* 5. Declarations for the component parameters. This uses #define for
*    definition parameters and global variables for setting parameters.
* X. User declarations from component definitions.
* X. Declarations of variables for coordinate system transformations.
* X. Declaration of variables for neutron state.
* X. Function prototypes.
*******************************************************************************/


/* Functions for outputting code. */

/* Handle for output file. */
static FILE *output_handle = NULL;/* Handle for output file. */
static int num_next_output_line = 1; /* Line number for next output line. */
static char *quoted_output_file_name = NULL; /* str_quote()'ed name
                                                of output file. */

/* Convert instrument formal parameter type numbers to their enum name. */
char *instr_formal_type_names[] =
  { "instr_type_double", "instr_type_int", "instr_type_string" };

char *instr_formal_type_names_real[] =
  { "MCNUM", "int", "char*", "char"}; /* the last one is for static char allocation */

/*******************************************************************************
* Output a line of code
* Assumes that the output does not contain newlines.
*******************************************************************************/
static void
cout(char *s)
{
  fprintf(output_handle, "%s\n", s);
  num_next_output_line++;
}

/*******************************************************************************
* Output a line of code using printf-style format string.
* Assumes that the output does not contain newlines.
*******************************************************************************/
static void
coutf(char *format, ...)
{
  va_list ap;

  va_start(ap, format);
  vfprintf(output_handle, format, ap);
  va_end(ap);
  fprintf(output_handle, "\n");
  num_next_output_line++;
}

/*******************************************************************************
* Output #line directive to handle code coming from a different file.
* The filename is assumed to be already properly quoted for special chars.
*******************************************************************************/
static void
code_set_source(char *filename, int linenum)
{
  if(linenum > 0)
    coutf("#line %d \"%s\"", linenum, filename);
}

/*******************************************************************************
* Output #line directive to reset back to the generated output C file.
*******************************************************************************/
static void
code_reset_source(void)
{
  /* Note: the number after #line refers to the line AFTER the directive. */
  coutf("#line %d \"%s\"", num_next_output_line + 1, quoted_output_file_name);
}


static void
codeblock_out(struct code_block *code)
{
  List_handle liter;                /* For list iteration. */
  char *line;                        /* Single code line. */

  if(list_len(code->lines) <= 0)
    return;
  code_set_source(code->quoted_filename, code->linenum + 1);
  liter = list_iterate(code->lines);
  while(line = list_next(liter))
  {
    fprintf(output_handle, "%s", line);
    num_next_output_line++;
  }
  list_iterate_end(liter);
  code_reset_source();
}

static void
codeblock_out_brace(struct code_block *code)
{
  List_handle liter;                /* For list iteration. */
  char *line;                        /* Single code line. */

  if(list_len(code->lines) <= 0)
    return;
  code_set_source(code->quoted_filename, code->linenum);
  cout("{");
  liter = list_iterate(code->lines);
  while(line = list_next(liter))
  {
    fprintf(output_handle, "%s", line);
    num_next_output_line++;
  }
  list_iterate_end(liter);
  cout("}");
  code_reset_source();
}


struct code_block *
codeblock_new(void)
{
  struct code_block *cb;

  palloc(cb);
  cb->filename = NULL;
  cb->quoted_filename = NULL;
  cb->linenum  = -1;
  cb->lines    = list_create();
  return cb;
}

/*******************************************************************************
* Read a file and output it to the generated simulation code. Uses a
* fixed-size buffer, and will silently and arbitrarily break long lines.
*******************************************************************************/
static void
embed_file(char *name)
{
  char buf[4096];
  FILE *f;
  int last;

  if (!symtab_lookup(lib_instances, name))
  {
    /* First look in the system directory. */
    f = open_file_search_sys(name);
    /* If not found, look in the full search path. */
    if(f == NULL) {
      f = open_file_search(name);
      /* If still not found, abort. */
      if(f == NULL)
        fatal_error("Could not find file '%s'\n", name);
      else if (verbose) printf("Embedding file      %s (user path)\n", name);
    } else if (verbose) printf("Embedding file      %s (%s)\n", name, get_sys_dir());

    cout("");
    code_set_source(name, 1);
    /* Now loop, reading lines and outputting them in the code. */
    while(!feof(f))
    {
      if(fgets(buf, 4096, f) == NULL)
        break;
      last = strlen(buf) - 1;
      if(last >= 0 && (buf[last] == '\n' || buf[last] == '\r'))
        buf[last--] = '\0';
      if(last >= 0 && (buf[last] == '\n' || buf[last] == '\r'))
        buf[last--] = '\0';
      cout(buf);
    }
    fclose(f);
    coutf("/* End of file \"%s\". */", name);
    cout("");
    code_reset_source();
    symtab_add(lib_instances, name, NULL);
  } /* else file has already been embedded */
}


/*******************************************************************************
* The following two functions output #define directives around a given piece
* of code to set up the right variable names (eg. the proper scope) for
* instrument and component parameters. The functions are recursive on the
* parameter lists.
*
* The functions first output an appropriate list of #define's, then call the
* supplied function func with the argument data, and finally outputs a
* matching list of #undef's.
*******************************************************************************/
static void cogen_instrument_scope_rec(List_handle parlist,
                                       void (*func)(void *), void *data)
{
  struct instr_formal *par;

  par = list_next(parlist);
  if(par != NULL)
  {
    coutf("#define %s %sip%s", par->id, ID_PRE, par->id);
    cogen_instrument_scope_rec(parlist, func, data);
    coutf("#undef %s", par->id);
  }
  else
  {
    (*func)(data);
  }
}

static void
cogen_instrument_scope(struct instr_def *instr,
                       void (*func)(void *), void *data)
{
  List_handle parlist;

  coutf("#define %scompcurname %s", ID_PRE, instr->name);
  /* This simply starts up the recursion on parameters. */
  parlist = list_iterate(instr->formals);
  cogen_instrument_scope_rec(parlist, func, data);
  list_iterate_end(parlist);
  coutf("#undef %scompcurname", ID_PRE);
}

/* Create the bindings for the SETTING parameter scope. Since the types of
* setting parameters are known, local declarations can be used, avoiding the
* problems with #define macro definitions.
*/
static void
cogen_comp_scope_setpar(struct comp_inst *comp, List_handle set, int infunc,
                        void (*func)(void *), void *data)
{
  struct comp_iformal *formal;

  /* Get the next setting parameter. */
  formal = list_next(set);
  if(formal != NULL)
  {
    /* Create local parameter equal to global value. */
    if(infunc)
      coutf("%s %s = %sc%s_%s;", instr_formal_type_names_real[formal->type], formal->id, ID_PRE, comp->name, formal->id);
    else
      coutf("#define %s %sc%s_%s", formal->id, ID_PRE, comp->name, formal->id);
    cogen_comp_scope_setpar(comp, set, infunc, func, data);

    if(!infunc)
      coutf("#undef %s", formal->id);
  }
  else
  {
    (*func)(data);                /* Now do the body. */
    if(infunc == 2 && list_len(comp->extend->lines) > 0)
    {
      coutf("/* '%s' component extend code */",comp->name);
      coutf("    SIG_MESSAGE(\"%s (Trace:Extend)\");", comp->name); /* ADD: E. Farhi Aug 25th, 2002 */
      codeblock_out(comp->extend);
    }
  }
}

/* Create the #define statements to set up the scope for DEFINITION and OUTPUT
* parameters.
*/
static void
cogen_comp_scope_rec(struct comp_inst *comp, List_handle def, List set_list,
                     List_handle out, int infunc,
                     void (*func)(void *), void *data)
{
  char *par;
  struct comp_iformal *formal;

  /* First get the next DEFINITION or OUTPUT parameter, if any. */
  if(def != NULL)
  {
    formal = list_next(def);
    if(formal == NULL)
      def = NULL;                /* Now finished with definition parameters. */
    else
      par = formal->id;
  }
  if(def == NULL)
    par = list_next(out);
  if(par != NULL)
  {
    /* Create #define / #undef pair for this parameter around rest of code. */
    coutf("#define %s %sc%s_%s", par, ID_PRE, comp->name, par);
    cogen_comp_scope_rec(comp, def, set_list, out, infunc, func, data);
    coutf("#undef %s", par);
  }
  else
  { /* Now do the SETTING parameters. */
    List_handle set;

    if(infunc && list_len(set_list) > 0)
      coutf("{   /* Declarations of SETTING parameters. */");
    set = list_iterate(set_list);
    cogen_comp_scope_setpar(comp, set, infunc, func, data);
    list_iterate_end(set);
    if(infunc && list_len(set_list) > 0)
      coutf("}   /* End of SETTING parameter declarations. */");
  }
}

static void
cogen_comp_scope(struct comp_inst *comp, int infunc,
                 void (*func)(void *), void *data)
{
  List_handle def, out;

  coutf("#define %scompcurname  %s", ID_PRE, comp->name);
  coutf("#define %scompcurtype  %s", ID_PRE, comp->type);
  coutf("#define %scompcurindex %i", ID_PRE, comp->index);
  def = list_iterate(comp->def->def_par);
  out = list_iterate(comp->def->out_par);
  cogen_comp_scope_rec(comp, def, comp->def->set_par, out,
                       infunc, func, data);
  list_iterate_end(out);
  list_iterate_end(def);
  coutf("#undef %scompcurname", ID_PRE);
  coutf("#undef %scompcurtype", ID_PRE);
  coutf("#undef %scompcurindex", ID_PRE);
}


/*******************************************************************************
* Generate declarations from users declaration section in component definition.
*******************************************************************************/
static void
cogen_comp_decls_doit(void *arg)
{
  struct comp_inst *comp = arg;

  /* Output the user declaration code block. */
  if (list_len(comp->def->decl_code->lines) > 0)
    codeblock_out(comp->def->decl_code);
}

static void
cogen_comp_decls(struct comp_inst *comp)
{
  cogen_comp_scope(comp, 0, cogen_comp_decls_doit, comp);
}

static void
cogen_comp_shares(struct comp_inst *comp)
{
  /* Output the 'share' declaration code block
    (once for all same components)*/

  if (comp->def->comp_inst_number < 0)
  {
    coutf("/* Shared user declarations for all components '%s'. */", comp->def->name);
    codeblock_out(comp->def->share_code);
    comp->def->comp_inst_number *= -1;
  }
}


/*******************************************************************************
* Generate declaration part of code.
*******************************************************************************/

static void
cogen_decls(struct instr_def *instr)
{
  List_handle liter;                /* For list iteration. */
  struct comp_iformal *c_formal;/* Name of component formal input parameter */
  struct instr_formal *i_formal;/* Name of instrument formal parameter. */
  struct comp_inst *comp;       /* Component instance. */
  int    index = 0;        /* ADD: E. Farhi Sep 20th, 2001 index of comp instance */
  struct group_inst *group;     /* ADD: E. Farhi Sep 24th, 2001 group instances */

  /* 1. Function prototypes. */
  coutf("void %sinit(void);", ID_PRE);
  coutf("void %sraytrace(void);", ID_PRE);
  coutf("void %ssave(FILE *);", ID_PRE);
  coutf("void %sfinally(void);", ID_PRE);
  coutf("void %sdisplay(void);", ID_PRE);
  cout("");

  if(instr->nxdinfo->any) {
    coutf("/* Init NeXus file support declarations, using the NeXus Dictionary API */");
    cout("#include \"nxdict.h\"");
    coutf("void %snxdict_init(void); ", ID_PRE);
    coutf("void %snxdict_cleanup(void); ", ID_PRE);
    coutf("void %snxdict_nxout(void); ", ID_PRE);
  }

  /* 2. Component SHAREs. */
  liter = list_iterate(instr->complist);
  while(comp = list_next(liter))
  {
    if((list_len(comp->def->share_code->lines) > 0) && (comp->def->comp_inst_number < 0))
    {
      cogen_comp_shares(comp);
      cout("");
    }
  }
  list_iterate_end(liter);

  /* 3. Global variables for instrument parameters. */
  cout("/* Instrument parameters. */");
  liter = list_iterate(instr->formals);
  while(i_formal = list_next(liter))
  {
    coutf("%s " ID_PRE "ip%s;", instr_formal_type_names_real[i_formal->type], i_formal->id);
  }
  list_iterate_end(liter);
  cout("");

  /* 4. Table of instrument parameters. */
  coutf("#define %sNUMIPAR %d", ID_PRE, list_len(instr->formals));
  coutf("int %snumipar = %d;", ID_PRE, list_len(instr->formals));
  coutf("struct %sinputtable_struct %sinputtable[%sNUMIPAR+1] = {",
        ID_PRE, ID_PRE, ID_PRE);
  liter = list_iterate(instr->formals);
  while(i_formal = list_next(liter))
  {
    if (i_formal->isoptional && !strcmp(instr_formal_type_names[i_formal->type],"instr_type_string"))
      coutf("  \"%s\", &%sip%s, %s, %s, ", i_formal->id, ID_PRE,
          i_formal->id, instr_formal_type_names[i_formal->type],
          exp_tostring(i_formal->default_value));
    else
      coutf("  \"%s\", &%sip%s, %s, \"%s\", ", i_formal->id, ID_PRE, i_formal->id,
          instr_formal_type_names[i_formal->type],
          i_formal->isoptional ? exp_tostring(i_formal->default_value) : "");
  }
  list_iterate_end(liter);
  coutf("  NULL, NULL, instr_type_double, \"\"");
  coutf("};");  /* 5. Declaration of component definition and setting parameters. */
  cout("");

  /* 5. User's declarations from the instrument definition file. */
  cout("/* User declarations from instrument definition. */");
  cogen_instrument_scope(instr, (void (*)(void *))codeblock_out, instr->decls);
  cout("");

  /* 6. Table to store neutron states when entering each component */
  cout("/* Neutron state table at each component input (local coords) */");
  cout("/* [x, y, z, vx, vy, vz, t, sx, sy, sz, p] */");
  coutf("MCNUM %scomp_storein[11*%i];", ID_PRE, list_len(instr->complist)+2);

  /* 7. Table to store position (abs/rel) for each component */
  cout("/* Components position table (absolute and relative coords) */");
  coutf("Coords %scomp_posa[%i];", ID_PRE, list_len(instr->complist)+2);
  coutf("Coords %scomp_posr[%i];", ID_PRE, list_len(instr->complist)+2);
  cout("/* Counter for each comp to check for inactive ones */");
  coutf("MCNUM  %sNCounter[%i];", ID_PRE, list_len(instr->complist)+2);
  cout("/* Counter for PROP ABSORB */");
  coutf("MCNUM  %sAbsorbProp[%i];", ID_PRE, list_len(instr->complist)+2);

  /* 8. Declaration of group flags */
  cout("/* Flag true when previous component acted on the neutron (SCATTER) */");
  coutf("MCNUM %sScattered=0;", ID_PRE);

  if (list_len(instr->grouplist) > 0)
  {
    cout("/* Component group definitions (flags) */");
    liter = list_iterate(instr->grouplist);
    while(group = list_next(liter))
    {
      coutf("char %sGroup%s=0;", ID_PRE, group->name);
    }
    list_iterate_end(liter);
  }

  /* 9. Declaration of component definition/setting parameters */
  cout("/* Declarations of component definition and setting parameters. */");
  cout("");
  index = 0;
  liter = list_iterate(instr->complist);
  while(comp = list_next(liter))
  {
    List_handle liter2;

    index++;
    comp->index = index;

    if(list_len(comp->def->def_par) > 0)
    {                                /* (The if avoids a redundant comment.) */
      coutf("/* Definition parameters for component '%s' [%i]. */", comp->name, index);
      liter2 = list_iterate(comp->def->def_par);
      while(c_formal = list_next(liter2))
      {
        struct Symtab_entry *entry = symtab_lookup(comp->defpar, c_formal->id);
        char *val = exp_tostring(entry->val);
        coutf("#define %sc%s_%s %s", ID_PRE, comp->name, c_formal->id, val);
        str_free(val);
      }
      list_iterate_end(liter2);
    }
    if(list_len(comp->def->set_par) > 0)
    {
      coutf("/* Setting parameters for component '%s' [%i]. */", comp->name, index);
      liter2 = list_iterate(comp->def->set_par);
      while(c_formal = list_next(liter2))
      {
        if (c_formal->type != instr_type_string)
          coutf("%s %sc%s_%s;", instr_formal_type_names_real[c_formal->type], ID_PRE, comp->name, c_formal->id);
        else  /* char type for component */
          coutf("%s %sc%s_%s[1024];", instr_formal_type_names_real[c_formal->type+1], ID_PRE, comp->name, c_formal->id);
      }
      list_iterate_end(liter2);
    }
    if(list_len(comp->def->def_par) > 0 || list_len(comp->def->set_par) > 0)
      cout("");
  }
  list_iterate_end(liter);

  /* 10. User declarations from component definitions (for each instance). */
  cout("/* User component declarations. */");
  cout("");
  liter = list_iterate(instr->complist);
  while(comp = list_next(liter))
  {
    if((list_len(comp->def->decl_code->lines) > 0) || (comp->def->comp_inst_number < 0))
    {
      coutf("/* User declarations for component '%s' [%i]. */", comp->name, index);
      cogen_comp_decls(comp);
      cout("");
    }
  }
  list_iterate_end(liter);

  /* 11. Declarations for the position and rotation transformations between
     coordinate systems of components. */
  liter = list_iterate(instr->complist);
  while(comp = list_next(liter))
  {
    coutf("Coords %sposa%s, %sposr%s;", ID_PRE, comp->name, ID_PRE, comp->name);
    coutf("Rotation %srota%s, %srotr%s;", ID_PRE, comp->name, ID_PRE, comp->name);
  }
  list_iterate_end(liter);
  cout("");

  /* 12. Neutron state. */
  coutf("MCNUM %snx, %sny, %snz, %snvx, %snvy, %snvz, %snt, "
        "%snsx, %snsy, %snsz, %snp;",
        ID_PRE, ID_PRE, ID_PRE, ID_PRE, ID_PRE, ID_PRE, ID_PRE,
        ID_PRE, ID_PRE, ID_PRE, ID_PRE);
  cout("");

}


/*******************************************************************************
* Code generation for any NEXUS declarations.
*******************************************************************************/

/* this code generation comes after the 'init' code generation, thus comp
   parameters are known, and can be saved within nxdict_init */

static void
cogen_nxdict(struct instr_def *instr)
{
  List_handle liter;
  struct comp_inst *comp;
  struct instr_formal *i_formal;
  char *quoted_name = str_quote(instr->nxdinfo->nxdfile);
  /* now create Instrument parameter list to be sent to NXdict routines */

  coutf("  SIG_MESSAGE(\"%s (NeXus init)\");", instr->name); /* ADD: E. Farhi Aug 25th, 2002 */
}


/*******************************************************************************
* Generate the ##init() function.
*******************************************************************************/
static void
cogen_init(struct instr_def *instr)
{
  List_handle liter;
  struct comp_inst *comp, *last;
  char *d2r;

  coutf("void %sinit(void) {", ID_PRE);

  /* User initializations from instrument definition. */
  cogen_instrument_scope(instr, (void (*)(void *))codeblock_out_brace,
                         instr->inits);

  /* MOD: E. Farhi Sep 20th, 2001 moved transformation block so that */
  /*                              it can be used in following init block */

  /* Compute the necessary vectors and transformation matrices for coordinate
     system changes between components. */
  cout("  /* Computation of coordinate transformations. */");
  cout("  {");
  coutf("    Coords %stc1, %stc2;", ID_PRE, ID_PRE);
  coutf("    Rotation %str1;", ID_PRE);
  cout("");
  /* Conversion factor degrees->radians for rotation angles. */
  d2r = "DEG2RAD";

  liter = list_iterate(instr->complist);
  last = NULL;
  coutf("    %sDEBUG_INSTR()", ID_PRE);
  while((comp = list_next(liter)) != NULL)
  {
    struct comp_inst *relcomp; /* Component relative to. */
    char *x, *y, *z;

    coutf("    /* Component %s. */", comp->name);
    coutf("    SIG_MESSAGE(\"%s (Init:Place/Rotate)\");", comp->name); /* ADD: E. Farhi Sep 20th, 2001 */

    /* Absolute rotation. */
    x = exp_tostring(comp->pos->orientation.x);
    y = exp_tostring(comp->pos->orientation.y);
    z = exp_tostring(comp->pos->orientation.z);
    relcomp = comp->pos->orientation_rel;
    if(relcomp == NULL)
    {                                /* Absolute orientation. */
      coutf("    rot_set_rotation(%srota%s,", ID_PRE, comp->name);
      code_set_source(instr->quoted_source,
                      exp_getlineno(comp->pos->orientation.x));
      coutf("      (%s)*%s,", x, d2r);
      code_set_source(instr->quoted_source,
                      exp_getlineno(comp->pos->orientation.y));
      coutf("      (%s)*%s,", y, d2r);
      code_set_source(instr->quoted_source,
                      exp_getlineno(comp->pos->orientation.z));
      coutf("      (%s)*%s);", z, d2r);
      code_reset_source();
    }
    else
    {
      coutf("    rot_set_rotation(%str1,", ID_PRE);
      code_set_source(instr->quoted_source,
                      exp_getlineno(comp->pos->orientation.x));
      coutf("      (%s)*%s,", x, d2r);
      code_set_source(instr->quoted_source,
                      exp_getlineno(comp->pos->orientation.y));
      coutf("      (%s)*%s,", y, d2r);
      code_set_source(instr->quoted_source,
                      exp_getlineno(comp->pos->orientation.z));
      coutf("      (%s)*%s);", z, d2r);
      code_reset_source();
      coutf("    rot_mul(%str1, %srota%s, %srota%s);",
            ID_PRE, ID_PRE, relcomp->name, ID_PRE, comp->name);
    }
    str_free(z);
    str_free(y);
    str_free(x);

    /* Relative rotation. */
    if(last == NULL)
    {                                /* First component. */
      coutf("    rot_copy(%srotr%s, %srota%s);",
            ID_PRE, comp->name, ID_PRE, comp->name);
    }
    else
    {
      coutf("    rot_transpose(%srota%s, %str1);", ID_PRE, last->name, ID_PRE);
      coutf("    rot_mul(%srota%s, %str1, %srotr%s);",
            ID_PRE, comp->name, ID_PRE, ID_PRE, comp->name);
    }

    /* Absolute position. */
    x = exp_tostring(comp->pos->place.x);
    y = exp_tostring(comp->pos->place.y);
    z = exp_tostring(comp->pos->place.z);
    relcomp = comp->pos->place_rel;
    if(relcomp == NULL)
    {
      coutf("    %sposa%s = coords_set(", ID_PRE, comp->name);
      code_set_source(instr->quoted_source, exp_getlineno(comp->pos->place.x));
      coutf("      %s,", x);
      code_set_source(instr->quoted_source, exp_getlineno(comp->pos->place.y));
      coutf("      %s,", y);
      code_set_source(instr->quoted_source, exp_getlineno(comp->pos->place.z));
      coutf("      %s);", z);
      code_reset_source();
    }
    else
    {
      coutf("    %stc1 = coords_set(", ID_PRE);
      code_set_source(instr->quoted_source, exp_getlineno(comp->pos->place.x));
      coutf("      %s,", x);
      code_set_source(instr->quoted_source, exp_getlineno(comp->pos->place.y));
      coutf("      %s,", y);
      code_set_source(instr->quoted_source, exp_getlineno(comp->pos->place.z));
      coutf("      %s);", z);
      code_reset_source();
      coutf("    rot_transpose(%srota%s, %str1);",
            ID_PRE, relcomp->name, ID_PRE);
      coutf("    %stc2 = rot_apply(%str1, %stc1);",
            ID_PRE, ID_PRE, ID_PRE);
      coutf("    %sposa%s = coords_add(%sposa%s, %stc2);",
            ID_PRE, comp->name, ID_PRE, relcomp->name, ID_PRE);
    }

    str_free(z);
    str_free(y);
    str_free(x);

    /* Relative position. */
    if(last == NULL)
      coutf("    %stc1 = coords_neg(%sposa%s);", ID_PRE, ID_PRE, comp->name);
    else
      coutf("    %stc1 = coords_sub(%sposa%s, %sposa%s);",
            ID_PRE, ID_PRE, last->name, ID_PRE, comp->name);
    coutf("    %sposr%s = rot_apply(%srota%s, %stc1);",
          ID_PRE, comp->name, ID_PRE, comp->name, ID_PRE);

    coutf("    %sDEBUG_COMPONENT(\"%s\", %sposa%s, %srota%s)",
          ID_PRE, comp->name, ID_PRE, comp->name, ID_PRE, comp->name);

    coutf("    %scomp_posa[%i] = %sposa%s;", ID_PRE, comp->index, ID_PRE, comp->name);
    coutf("    %scomp_posr[%i] = %sposr%s;", ID_PRE, comp->index, ID_PRE, comp->name);
    coutf("    %sNCounter[%i]  = 0;", ID_PRE, comp->index);
    coutf("    %sAbsorbProp[%i]= 0;", ID_PRE, comp->index);

    last = comp;
  }
  list_iterate_end(liter);

  /* Initialization of component setting parameters and user initialization
     code. */
  cout("  /* Component initializations. */");
  liter = list_iterate(instr->complist);
  while((comp = list_next(liter)) != NULL)
  {
    List_handle setpar;
    struct comp_iformal *par;

    coutf("  /* Initializations for component %s. */", comp->name);
    coutf("  SIG_MESSAGE(\"%s (Init)\");", comp->name); /* ADD: E. Farhi Sep 20th, 2001 */
    /* Initialization of the component setting parameters. */
    setpar = list_iterate(comp->def->set_par);
    while((par = list_next(setpar)) != NULL)
    {
      char *val;
      struct Symtab_entry *entry;

      entry = symtab_lookup(comp->setpar, par->id);
      val = exp_tostring(entry->val);
      code_set_source(instr->quoted_source, exp_getlineno(entry->val));
      if (par->type != instr_type_string)
      {
        coutf("  %sc%s_%s = %s;", ID_PRE, comp->name, par->id, val);
      }
      else
      {
        coutf("  if(%s) strncpy(%sc%s_%s,%s, 1024); else %sc%s_%s[0]='\\0';", val, ID_PRE, comp->name, par->id, val, ID_PRE, comp->name, par->id);
      }
      str_free(val);
    }
    list_iterate_end(setpar);
    if(list_len(comp->def->set_par) > 0)
      code_reset_source();
    cout("");

    /* Users initializations. */
    if(list_len(comp->def->init_code->lines) > 0)
      cogen_comp_scope(comp, 0, (void (*)(void *))codeblock_out_brace,
                            comp->def->init_code);
    cout("");
  }
  list_iterate_end(liter);

  if(instr->nxdinfo->any) {
    coutf("#ifdef NXDICTAPI");
    coutf("  %snxdict_init(); ", ID_PRE);
    coutf("#endif");
  }

  /* Output graphics representation of components. */
  coutf("    if(%sdotrace) %sdisplay();", ID_PRE, ID_PRE);
  coutf("    %sDEBUG_INSTR_END()", ID_PRE);
  cout("  }");
  cout("");

  cout("}");
  cout("");
}

static void
cogen_trace(struct instr_def *instr)
{
  List_handle liter;
  struct comp_inst *comp;
  struct group_inst *group;
  char   is_in_group=0;
  char  *last_group_name;

  /* Output the function header. */
  coutf("void %sraytrace(void) {", ID_PRE);

  /* Local neutron state. */
  cout("  /* Copy neutron state to local variables. */");
  coutf("  MCNUM %snlx = %snx;", ID_PRE, ID_PRE);
  coutf("  MCNUM %snly = %sny;", ID_PRE, ID_PRE);
  coutf("  MCNUM %snlz = %snz;", ID_PRE, ID_PRE);
  coutf("  MCNUM %snlvx = %snvx;", ID_PRE, ID_PRE);
  coutf("  MCNUM %snlvy = %snvy;", ID_PRE, ID_PRE);
  coutf("  MCNUM %snlvz = %snvz;", ID_PRE, ID_PRE);
  coutf("  MCNUM %snlt = %snt;", ID_PRE, ID_PRE);
  coutf("  MCNUM %snlsx = %snsx;", ID_PRE, ID_PRE);
  coutf("  MCNUM %snlsy = %snsy;", ID_PRE, ID_PRE);
  coutf("  MCNUM %snlsz = %snsz;", ID_PRE, ID_PRE);
  coutf("  MCNUM %snlp = %snp;", ID_PRE, ID_PRE);
  cout("");

  /* Debugging (initial state). */
  coutf("  %sDEBUG_ENTER()", ID_PRE);
  coutf("  %sDEBUG_STATE(%snlx, %snly, %snlz, %snlvx, %snlvy, %snlvz,"
        "%snlt,%snlsx,%snlsy, %snlp)",
        ID_PRE, ID_PRE, ID_PRE, ID_PRE, ID_PRE, ID_PRE, ID_PRE,
        ID_PRE, ID_PRE, ID_PRE, ID_PRE);

  /* ADD: E. Farhi Sep 25th, 2001 Set group flags */
  if (list_len(instr->grouplist) > 0)
  {
    cout("/* Set Component group definitions (flags) */");
    liter = list_iterate(instr->grouplist);
    while(group = list_next(liter))
    {
      coutf("  %sGroup%s=0;", ID_PRE, group->name);
    }
    list_iterate_end(liter);
  }
  coutf("#define %sabsorb %sabsorbAll", ID_PRE, ID_PRE);

  /* Now the trace code for each component. Proper scope is set up for each
     component using #define/#undef. */
  liter = list_iterate(instr->complist);
  while((comp = list_next(liter)) != NULL)
  {
    char *statepars[10];
    static char *statepars_names[10] =
      {
        "nlx", "nly", "nlz", "nlvx", "nlvy", "nlvz",
        "nlt", "nlsx", "nlsy", "nlp"
      };
    int i;
    List_handle statepars_handle;

    coutf("  /* TRACE Component %s. */", comp->name);
    coutf("  SIG_MESSAGE(\"%s (Trace)\");", comp->name); /* ADD: E. Farhi Sep 20th, 2001 */
    coutf("  %sDEBUG_COMP(\"%s\")", ID_PRE, comp->name);
    /* Change of coordinates. */
    coutf("  %scoordschange(%sposr%s, %srotr%s,", ID_PRE, ID_PRE, comp->name,
          ID_PRE, comp->name);
    coutf("    &%snlx, &%snly, &%snlz,", ID_PRE, ID_PRE, ID_PRE);
    coutf("    &%snlvx, &%snlvy, &%snlvz,", ID_PRE, ID_PRE, ID_PRE);
    coutf("    &%snlt, &%snlsx, &%snlsy);", ID_PRE, ID_PRE, ID_PRE);
    if(instr->polarised)
      coutf("  %scoordschange_polarisation("
            "%srotr%s, &%snlsx, &%snlsy, &%snlsz);",
            ID_PRE, ID_PRE, comp->name, ID_PRE, ID_PRE, ID_PRE);

    /* Debugging (entry into component). */
    coutf("  %sDEBUG_STATE(%snlx, %snly, %snlz, %snlvx, %snlvy, %snlvz,"
          "%snlt,%snlsx,%snlsy, %snlp)",
          ID_PRE, ID_PRE, ID_PRE, ID_PRE, ID_PRE, ID_PRE, ID_PRE,
          ID_PRE, ID_PRE, ID_PRE, ID_PRE);

    /* Trace code. */
    for(i = 0; i < 10; i++)
      statepars[i] = NULL;
    statepars_handle = list_iterate(comp->def->state_par);
    for(i = 0; i < 10; i++)
    {
      statepars[i] = list_next(statepars_handle);
      if(statepars[i] == NULL)
        break;
    }
    list_iterate_end(statepars_handle);
    for(i = 0; i < 10; i++)
    {
      if(statepars[i] != NULL)
        coutf("#define %s %s%s", statepars[i], ID_PRE, statepars_names[i]);
      else
        break;
    }
    if(comp->def->polarisation_par)
    {
      coutf("#define %s %s%s", comp->def->polarisation_par[0], ID_PRE, "nlsx");
      coutf("#define %s %s%s", comp->def->polarisation_par[1], ID_PRE, "nlsy");
      coutf("#define %s %s%s", comp->def->polarisation_par[2], ID_PRE, "nlsz");
    }
    /* ADD: E. Farhi Sep 20th, 2001 store neutron state in mccomp_storein */
    coutf("  STORE_NEUTRON(%i,%snlx, %snly, %snlz, %snlvx,"
          "%snlvy,%snlvz,%snlt,%snlsx,%snlsy, %snlsz, %snlp);",
          comp->index, ID_PRE, ID_PRE, ID_PRE, ID_PRE, ID_PRE, ID_PRE,
          ID_PRE, ID_PRE, ID_PRE, ID_PRE, ID_PRE, ID_PRE);
    coutf("  %sScattered=0;", ID_PRE);
    coutf("  %sNCounter[%i]++;", ID_PRE, comp->index);
    if (comp->group != NULL)
    {
      coutf("  if (!%sGroup%s)", ID_PRE, comp->group->name);
      cout("  {");
      coutf("#undef %sabsorb", ID_PRE);
      coutf("#define %sabsorb %sabsorbComp%s", ID_PRE, ID_PRE, comp->name);
      is_in_group =1;
      last_group_name = comp->group->name;
    }
    else
    if (is_in_group)
    { /* this comp is not in a group, but previous was */
      is_in_group =0;
      coutf("  /* Leave %s group thus absorb non scattered neutrons */", last_group_name);
      coutf("  if (!%sGroup%s) ABSORB;", ID_PRE, last_group_name);
    }
    cogen_comp_scope(comp, 2, (void (*)(void *))codeblock_out_brace,
                     comp->def->trace_code);
    if (comp->group != NULL)
    {
      coutf("#undef %sabsorb", ID_PRE);
      coutf("#define %sabsorb %sabsorbAll", ID_PRE, ID_PRE);
      coutf("  } /* end comp %s in group %s */", comp->name, comp->group->name);
      coutf("  if (%sScattered) %sGroup%s=%i;", ID_PRE, ID_PRE, comp->group->name, comp->index);
      cout("  /* Label to skip component instead of absorb */");
      coutf("  %sabsorbComp%s:", ID_PRE, comp->name);
      coutf("  if (!%sGroup%s)", ID_PRE, comp->group->name);
      coutf("    { RESTORE_NEUTRON(%i,%snlx, %snly, %snlz, %snlvx,"
          "%snlvy,%snlvz,%snlt,%snlsx,%snlsy, %snlsz, %snlp); }",
          comp->index, ID_PRE, ID_PRE, ID_PRE, ID_PRE, ID_PRE, ID_PRE,
          ID_PRE, ID_PRE, ID_PRE, ID_PRE, ID_PRE, ID_PRE);
    }
    if(comp->def->polarisation_par)
    {
      coutf("#undef %s", comp->def->polarisation_par[2]);
      coutf("#undef %s", comp->def->polarisation_par[1]);
      coutf("#undef %s", comp->def->polarisation_par[0]);
    }
    for(i = 9; i >= 0; i--)
    {
      if(statepars[i] != NULL)
        coutf("#undef %s", statepars[i]);
    }
    /* Debugging (exit from component). */
    coutf("  %sDEBUG_STATE(%snlx, %snly, %snlz, %snlvx, %snlvy, %snlvz,"
          "%snlt,%snlsx,%snlsy, %snlp)",
          ID_PRE, ID_PRE, ID_PRE, ID_PRE, ID_PRE, ID_PRE, ID_PRE,
          ID_PRE, ID_PRE, ID_PRE, ID_PRE);
    cout("");

  }
  list_iterate_end(liter);

  /* Absorbing neutrons - goto this label to skip remaining components. */
  coutf(" %sabsorbAll:", ID_PRE);

  /* Debugging (final state). */
  coutf("  %sDEBUG_LEAVE()", ID_PRE);
  coutf("  %sDEBUG_STATE(%snlx, %snly, %snlz, %snlvx, %snlvy, %snlvz,"
        "%snlt,%snlsx,%snlsy, %snlp)",
        ID_PRE, ID_PRE, ID_PRE, ID_PRE, ID_PRE, ID_PRE, ID_PRE,
        ID_PRE, ID_PRE, ID_PRE, ID_PRE);


  /* Copy back neutron state to global variables. */
  /* ToDo: Currently, this will be in the local coordinate system of the last
     component - should be transformed back into the global system. */
  cout("  /* Copy neutron state to global variables. */");
  coutf("  %snx = %snlx;", ID_PRE, ID_PRE);
  coutf("  %sny = %snly;", ID_PRE, ID_PRE);
  coutf("  %snz = %snlz;", ID_PRE, ID_PRE);
  coutf("  %snvx = %snlvx;", ID_PRE, ID_PRE);
  coutf("  %snvy = %snlvy;", ID_PRE, ID_PRE);
  coutf("  %snvz = %snlvz;", ID_PRE, ID_PRE);
  coutf("  %snt = %snlt;", ID_PRE, ID_PRE);
  coutf("  %snsx = %snlsx;", ID_PRE, ID_PRE);
  coutf("  %snsy = %snlsy;", ID_PRE, ID_PRE);
  coutf("  %snsz = %snlsz;", ID_PRE, ID_PRE);
  coutf("  %snp = %snlp;", ID_PRE, ID_PRE);

  /* Function end. */
  cout("}");
  cout("");
}

static void
cogen_save(struct instr_def *instr)
{
  List_handle liter;             /* For list iteration. */
  struct comp_inst *comp;        /* Component instance. */

  /* User SAVE code from component definitions (for each instance). */
  coutf("void %ssave(FILE *handle) {", ID_PRE);
  /* In case the save occurs during simulation (-USR2 not at end), we must close
   * current siminfo and re-open it, not to have redundant monitor entries
   * saved each time for each monitor. The sim_info is then incomplete, but
   * data is saved entirely. It is completed during the last siminfo_close
   * of mcraytrace
   */
  cout("  if (!handle) mcsiminfo_init(NULL);");
  cout("  /* User component SAVE code. */");
  cout("");
  liter = list_iterate(instr->complist);
  while(comp = list_next(liter))
  {
    if(list_len(comp->def->save_code->lines) > 0)
    {
      coutf("  /* User SAVE code for component '%s'. */", comp->name);
      coutf("  SIG_MESSAGE(\"%s (Save)\");", comp->name); /* ADD: E. Farhi Sep 20th, 2001 */
      cogen_comp_scope(comp, 1, (void (*)(void *))codeblock_out_brace,
                       comp->def->save_code);
      cout("");
    }
  }
  list_iterate_end(liter);

  /* User's SAVE code from the instrument definition file. */
  if(list_len(instr->saves->lines) > 0)
  {
    cout("  /* User SAVE code from instrument definition. */");
    coutf("  SIG_MESSAGE(\"%s (Save)\");", instr->name);
    cogen_instrument_scope(instr, (void (*)(void *))codeblock_out_brace,
                           instr->saves);
    cout("");
  }
  cout("  if (!handle) mcsiminfo_close(); ");
  cout("}");
}


static void
cogen_finally(struct instr_def *instr)
{
  List_handle liter;                /* For list iteration. */
  struct comp_inst *comp;        /* Component instance. */

  /* User FINALLY code from component definitions (for each instance). */
  coutf("void %sfinally(void) {", ID_PRE);
  cout("  /* User component FINALLY code. */");
  /* first call SAVE code to save any remaining data */
  cout("  mcsiminfo_init(NULL);");
  coutf("  %ssave(%ssiminfo_file); /* save data when simulation ends */", ID_PRE, ID_PRE);
  cout("");
  liter = list_iterate(instr->complist);
  while(comp = list_next(liter))
  {
    if(list_len(comp->def->finally_code->lines) > 0)
    {
      coutf("  /* User FINALLY code for component '%s'. */", comp->name);
      coutf("  SIG_MESSAGE(\"%s (Finally)\");", comp->name); /* ADD: E. Farhi Sep 20th, 2001 */
      cogen_comp_scope(comp, 1, (void (*)(void *))codeblock_out_brace,
                       comp->def->finally_code);
      cout("");
    }
    coutf("    if (!%sNCounter[%i]) "
      "fprintf(stderr, \"Warning: No neutron could reach Component[%i] %s\\n\");",
      ID_PRE, comp->index, comp->index, comp->name);
    coutf("    if (%sAbsorbProp[%i]) "
      "fprintf(stderr, "
        "\"Warning: %%g events were removed in Component[%i] %s\\n"
        "         (negative time, rounding errors).\\n"
        "\", %sAbsorbProp[%i]);"
    , ID_PRE, comp->index, comp->index, comp->name, ID_PRE, comp->index);
  }
  list_iterate_end(liter);

  /* User's FINALLY code from the instrument definition file. */
  if(list_len(instr->finals->lines) > 0)
  {
    cout("  /* User FINALLY code from instrument definition. */");
    coutf("  SIG_MESSAGE(\"%s (Finally)\");", instr->name); /* ADD: E. Farhi Aug 25th, 2002 */
    cogen_instrument_scope(instr, (void (*)(void *))codeblock_out_brace,
                           instr->finals);
    cout("");
  }
  cout("  mcsiminfo_close(); ");
  cout("}");
}


static void
cogen_mcdisplay(struct instr_def *instr)
{
  List_handle liter;                /* For list iteration. */
  struct comp_inst *comp;        /* Component instance. */

  /* User FINALLY code from component definitions (for each instance). */
  cout("#define magnify mcdis_magnify");
  cout("#define line mcdis_line");
  cout("#define multiline mcdis_multiline");
  cout("#define circle mcdis_circle");
  coutf("void %sdisplay(void) {", ID_PRE);
  cout("  printf(\"MCDISPLAY: start\\n\");");
  cout("  /* Component MCDISPLAY code. */");
  cout("");
  liter = list_iterate(instr->complist);
  while(comp = list_next(liter))
  {
    if(list_len(comp->def->mcdisplay_code->lines) > 0)
    {
      char *quoted_name = str_quote(comp->name);
      coutf("  /* MCDISPLAY code for component '%s'. */", comp->name);
      coutf("  SIG_MESSAGE(\"%s (McDisplay)\");", comp->name); /* ADD: E. Farhi Sep 20th, 2001 */
      coutf("  printf(\"MCDISPLAY: component %%s\\n\", \"%s\");", quoted_name);
      cogen_comp_scope(comp, 1, (void (*)(void *))codeblock_out_brace,
                       comp->def->mcdisplay_code);
      cout("");
      str_free(quoted_name);
    }
  }
  list_iterate_end(liter);

  cout("  printf(\"MCDISPLAY: end\\n\");");
  cout("}");
  cout("#undef magnify");
  cout("#undef line");
  cout("#undef multiline");
  cout("#undef circle");
}


/*******************************************************************************
* Output code for the mcstas runtime system. Default is to copy the runtime
* code into the generated executable, to minimize problems with finding the
* right files during compilation and linking, but this may be changed using
* the --no-runtime compiler switch.
*******************************************************************************/
static void
cogen_runtime(struct instr_def *instr)
{
  char *sysdir_orig;
  char *sysdir_new;
  char  pathsep[3];
  int   i,j=0;
  /* handles Windows '\' chararcters for embedding sys_dir into source code */
  if (MC_PATHSEP_C != '\\') strcpy(pathsep, MC_PATHSEP_S); else strcpy(pathsep, "\\\\");
  sysdir_orig = get_sys_dir();
  sysdir_new  = (char *)mem(2*strlen(sysdir_orig));
  for (i=0; i < strlen(sysdir_orig); i++)
  {
    if (sysdir_orig[i] == '\\')
    { sysdir_new[j] = '\\'; j++; sysdir_new[j] = '\\'; }
    else sysdir_new[j] = sysdir_orig[i];
    j++;
  }
  sysdir_new[j] = '\0';
  if(instr->use_default_main)
    cout("#define MC_USE_DEFAULT_MAIN");
  if(instr->enable_trace)
    cout("#define MC_TRACE_ENABLED");
  if(instr->portable)
    cout("#define MC_PORTABLE");
  if(instr->include_runtime)
  {
    cout("#define MC_EMBEDDED_RUNTIME"); /* Some stuff will be static. */
    embed_file("mcstas-r.h");
    embed_file("mcstas-r.c");
  }
  else
  {
    coutf("#include \"%s%sshare%smcstas-r.h\"", sysdir_new, pathsep, pathsep);
    fprintf(stderr,"Dependency: %s.o\n", "mcstas-r");
    fprintf(stderr,"To make instrument %s, compile and link with these libraries\n", instrument_definition->quoted_source);
  }

  coutf("#ifdef MC_TRACE_ENABLED");
  coutf("int %straceenabled = 1;", ID_PRE);
  coutf("#else");
  coutf("int %straceenabled = 0;", ID_PRE);
  coutf("#endif");
  coutf("#define MCSTAS \"%s%s\"", sysdir_new,pathsep);
  coutf("int %sdefaultmain = %d;", ID_PRE, instr->use_default_main);
  coutf("char %sinstrument_name[] = \"%s\";", ID_PRE, instr->name);
  coutf("char %sinstrument_source[] = \"%s\";", ID_PRE, instr->source);
  if(instr->use_default_main)
    cout("int main(int argc, char *argv[]){return mcstas_main(argc, argv);}");
}


/*******************************************************************************
* Generate the output file (in C).
*******************************************************************************/
void
cogen(char *output_name, struct instr_def *instr)
{
  time_t t;
  char date[64];

  time(&t);
  strncpy(date, ctime(&t), 64);
  if (strlen(date)) date[strlen(date)-1] = '\0';

  /* Initialize output file. */
  if(!output_name || !output_name[0] || !strcmp(output_name, "-"))
  {
    output_handle = fdopen(1, "w");
    quoted_output_file_name = str_quote("<stdout>");
  }
  else
  {
    output_handle = fopen(output_name, "w");
    quoted_output_file_name = str_quote(output_name);
  }
  num_next_output_line = 1;
  if(output_handle == NULL)
    fatal_error("Error opening output file '%s'\n", output_name);

  cout("/* Automatically generated file. Do not edit. ");
  cout(" * Format:     ANSI C source code");
  cout(" * Creator:    McStas <http://neutron.risoe.dk>");
  coutf(" * Instrument: %s (%s)", instr->source, instr->name);
  coutf(" * Date:       %s", date);
  cout(" */\n");
  cout("");
  coutf("#define MCSTAS_VERSION \"%s\"", MCSTAS_VERSION);
  cogen_runtime(instr);
  cogen_decls(instr);
  cogen_init(instr);
  if(instr->nxdinfo->any)
    cogen_nxdict(instr);        /* Only if NEXUS is actually used */
  cogen_trace(instr);
  cogen_save(instr);
  cogen_finally(instr);
  cogen_mcdisplay(instr);
}


syntax highlighted by Code2HTML, v. 0.9.1