/*
+-------+-----------------+------+-----------------+-------+-----------------+
|Program| CGEN_4TH.C      |Header| 4TH.H           |Library| CEXT            |
+-------+-----------------+------+-----------------+-------+----------+------+
|HISTORY                                           |    Programmer    | Date |
+--------------------------------------------------+------------------+------+
| Turbo C V2.0 version                             | J.L. Bezemer     |311099|
+--------------------------------------------------+------------------+------+
|MODIFICATION LOG                                  |    Programmer    | Date |
+--------------------------------------------------+------------------+------+
| Removed Version4th                               | J.L. Bezemer     |011199|
| Added reliability check for Hcode                | J.L. Bezemer     |031199|
| Always return CodeSiz in ErrLine                 | J.L. Bezemer     |031199|
| Fixed gcc compiler warning concering (ERROR)     | J.L. Bezemer     |170601|
| Added SLEEP support                              | J.L. Bezemer     |031103|
| Added dormant HX support                         | J.L. Bezemer     |050104|
| Added U modifier in TailHcode[]                  | J.L. Bezemer     |120610|
| Added MAX-N constant to WriteDictLine()          | J.L. Bezemer     |121211|
| Fixed TurboC error in WriteDictLine()            | J.L. Bezemer     |290312|
+--------------------------------------------------+------------------+------+
|REMARKS                                           |    Programmer    | Date |
+--------------------------------------------------+------------------+------+
| None                                             |                  |      |
+--------------------------------------------------+------------------+------+

  Copyright (C) 1997,2012 J.L. Bezemer

  This file is part of 4tH

  4tH 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 3
  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.


4tH C source generator to dump the H-code in a C file, which can be compiled
using any ANSI-C compiler and the 4tH library.

Prototype: void cgen_4th (Hcode *Obj, FILE *SourceFp)
Returns  : nothing
Memory   : none
Example  :


#include "4th.h"
#include <stdlib.h>

#ifndef ARCHAIC
  int main (int argc, char **argv)
#else
  int main (argc, argv) int argc; char **argv;
#endif

{
  Hcode *object;
  char  *sources;

  if (argc == 2)
    {
      if ((sources = open_4th (argv [1])) == NULL)
         printf ("Loading; \'%s\' does not exist or too large\n", argv [1]);
      else
        {
          object = comp_4th (sources);
          if (object)
              printf ("Compile; word %u: %s\n", object->ErrLine,
                     errs_4th [object->ErrNo]);
          cgen_4th (object, stdout);
          return (object->ErrNo ? EXIT_FAILURE : EXIT_SUCCESS);
        }
    }
  return (EXIT_FAILURE);
}


Input    : None
Output   : depends on program
Related  : save_4th(), hgen_4th()
*/

#ifdef USRLIB4TH
#include <4th.h>
#include <sys/cmds_4th.h>
#else
#include "4th.h"
#include "cmds_4th.h"
#endif

#include <stdarg.h>
                                       /* Hcode file header */
static char HeadHcode [] = "/*\n\
** This file was generated by 4tH\n\
** Copyright 1997,2010 by J.L. Bezemer\n\
*/\n\
\n\
#ifdef USRLIB4TH\n\
#include <4th.h>\n\
#else\n\
#include \"4th.h\"\n\
#endif\n\
\n\
#include <stdlib.h>\n\
\n\n\
static dict CodeSegment [] = {\n  ";

static char BodyHcode [] = "{\'\\x%02x\', %11ldL}\n};\n\n\
static char StringSegment [] = {\n  ";

static char TailHcode [] = "\'\\x00\'\n\
};\n\
\n\
static Hcode Object = {\n\
  %d, CodeSegment, %uU, StringSegment, NULL, NULL, 0, %uU, %uU, 0, 0, TRUE\n\
};\n\
\n\
\n\
#ifndef ARCHAIC\n\
  int main (int argc, char **argv)\n\
#else\n\
  int main (argc, argv) int argc; char **argv;\n\
#endif\n\
\n\
{\n\
  cell   Result;                       /* holds the result of the program */\n\
\n\
  fflush (stderr);                     /* flush any messages */\n\
                                       /* now execute it */\n\
  Result = exec_4th (&Object, argc, argv, 0);\n\
\n\
  fflush (stdout);\n\
\n\
  if (Object.ErrNo)                    /* show exit messages */\n\
     fprintf (stderr, \"Exiting; word %%u: %%s\\n\", Object.ErrLine,\n\
              errs_4th [Object.ErrNo]);\n\
  else\n\
     if (Result != CELL_MIN)\n\
        fprintf (stderr, \"Exiting; result: %%ld\\n\", Result);\n\
\n\
  return (Object.ErrNo \? EXIT_FAILURE : EXIT_SUCCESS);\n\
}\n";

static unsigned* WriteErr;


/*
This function does the actual writing of the C code to the device. If an
error occurs, it sets WriteError, which prevents further writing.
*/

#ifndef ARCHAIC
  static void WriteSource (FILE *SourceFp, char *Format, ...)
#else
  static void WriteSource (SourceFp, Format) FILE *SourceFp; char* Format;
#endif

{
  va_list  (args);
  va_start (args, Format);

  if (! *WriteErr)
     if (vfprintf (SourceFp, Format, args) == 0) *WriteErr = M4IOERR;

  va_end (args);
}


/*
This routine prints a single line of unsigned bytes to the output device.
*/

#ifndef ARCHAIC
  static void WriteStringLine (FILE* OutDev, unit *Buffer, unsigned MaxLen)
#else
  static void WriteStringLine (OutDev, Buffer, MaxLen) FILE* OutDev;
                               unit *Buffer; unsigned MaxLen;
#endif

{
  unsigned x;                          /* simple counter */

  for (x = 0; x < MaxLen; x++)         /* print all bytes */
      WriteSource (OutDev, "\'\\x%02x\', ", (int) Buffer [x]);
}


/*
This routine prints a single line of entries to the output device.
*/

#ifndef ARCHAIC
  static void WriteDictLine (FILE* OutDev, dict* Entry, unsigned MaxLen)
#else
  static void WriteDictLine (OutDev, Entry, MaxLen) FILE* OutDev; dict* Entry;
                             unsigned MaxLen;
#endif

{
  unsigned x;                          /* simple counter */

  for (x = 0; x < MaxLen; x++)         /* print all entries */
      if (Entry [x].Value == CELL_MIN) /* handle (ERROR) constant */
         WriteSource (OutDev, "{\'\\x%02x\',     CELL_MIN}, ",
                      Entry [x].Word); else
      if (Entry [x].Value == CELL_MAX) /* handle MAX-N constant */
         WriteSource (OutDev, "{\'\\x%02x\',     CELL_MAX}, ",
                      Entry [x].Word);
      else                             /* handle all other values */
         WriteSource (OutDev, "{\'\\x%02x\', %11ldL}, ",
                      Entry [x].Word, Entry [x].Value);
}


/*
This routine generates the C source for the Code Segment.
*/

#ifndef ARCHAIC
  static void WriteDictionary (Hcode *Obj, FILE *SourceFp)
#else
  static void WriteDictionary (Obj, SourceFp) Hcode *Obj; FILE *SourceFp;
#endif


{
  dict    *q;                          /* temporary pointer */
  unsigned x;                          /* simple counters */

  WriteSource (SourceFp, HeadHcode);   /* print header */
                                       /* print code segment */
  for (q = Obj->CodeSeg, x = Obj->CodeSiz - 1; x >= DICTSLINE;
       q += DICTSLINE, x -= DICTSLINE)
    {
      WriteDictLine (SourceFp, q, DICTSLINE);
      WriteSource (SourceFp, "\n  ");  /* print terminating EOL */
    }

  WriteDictLine (SourceFp, q, x);      /* print last line */
                                       /* print last entry */
  WriteSource (SourceFp, BodyHcode, Obj->CodeSeg [Obj->CodeSiz - 1].Word,
               Obj->CodeSeg [Obj->CodeSiz - 1].Value);
}


/*
This routine generates the C source for the String Segment.
*/

#ifndef ARCHAIC
  static void WriteStringConst (Hcode *Obj, FILE *SourceFp)
#else
  static void WriteStringConst (Obj, SourceFp) Hcode *Obj; FILE *SourceFp;
#endif

{
  unit    *p;                          /* temporary pointer */
  unsigned x;                          /* simple counters */

  if (Obj->StringSiz == 0)             /* print string segment */
     x = 1;
  else
    {
      for (p = (unit*) Obj->StringSeg, x = Obj->StringSiz - 1;
           x >= UNITSLINE; p += UNITSLINE, x -= UNITSLINE)
        {
          WriteStringLine (SourceFp, p, UNITSLINE);
          WriteSource (SourceFp, "\n  ");
        }                              /* print last EOL */
                                       /* print last line */
      WriteStringLine (SourceFp, p, x);
                                       /* print Hcode header */
      x = Obj->StringSiz;
    }

  WriteSource (SourceFp, TailHcode, Obj->CodeSiz, x, Obj->Variables,
               Obj->Strings);
}


/*
This function creates the standalone C source from Hcode. If an error
occurs during generation, the errorcode is stored in the Hcode header.
*/

#ifndef ARCHAIC
  void cgen_4th (Hcode *Obj, FILE *SourceFp)
#else
  void cgen_4th (Obj, SourceFp) Hcode *Obj; FILE *SourceFp;
#endif

{
  if (! Obj) return;                   /* check if object is reliable */
  else if (! Obj->Reliable) return;

  WriteErr     = &(Obj->ErrNo);
  Obj->ErrNo   = M4NOERRS;
  Obj->ErrLine = Obj->CodeSiz;

  WriteDictionary  (Obj, SourceFp);
  WriteStringConst (Obj, SourceFp);
}

