/* do not edit automatically generated by mc from mcComment.  */
/* mcComment.mod provides a module to remember the comments.

Copyright (C) 2015-2025 Free Software Foundation, Inc.
Contributed by Gaius Mulley <gaius.mulley@southwales.ac.uk>.

This file is part of GNU Modula-2.

GNU Modula-2 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, or (at your option)
any later version.

GNU Modula-2 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 GNU Modula-2; see the file COPYING3.  If not see
<http://www.gnu.org/licenses/>.  */

#include "config.h"
#include "system.h"
#include <stdbool.h>
#   if !defined (PROC_D)
#      define PROC_D
       typedef void (*PROC_t) (void);
       typedef struct { PROC_t proc; } PROC;
#   endif

#   if !defined (TRUE)
#      define TRUE (1==1)
#   endif

#   if !defined (FALSE)
#      define FALSE (1==0)
#   endif

#   include "GStorage.h"
#   include "Gmcrts.h"
#if defined(__cplusplus)
#   undef NULL
#   define NULL 0
#endif
#define _mcComment_C

#include "GmcComment.h"
#   include "GDynamicStrings.h"
#   include "GStorage.h"
#   include "GnameKey.h"
#   include "GmcDebug.h"
#   include "GASCII.h"
#   include "Glibc.h"

typedef struct mcComment__T1_r mcComment__T1;

typedef enum {mcComment_unknown, mcComment_procedureHeading, mcComment_inBody, mcComment_afterStatement} mcComment_commentType;

typedef mcComment__T1 *mcComment_commentDesc__opaque;

struct mcComment__T1_r {
                         mcComment_commentType type;
                         DynamicStrings_String content;
                         nameKey_Name procName;
                         bool used;
                       };


/*
   initComment - the start of a new comment has been seen by the lexical analyser.
                 A new comment block is created and all addText contents are placed
                 in this block.  onlySpaces indicates whether we have only seen
                 spaces on this line.
*/

extern "C" mcComment_commentDesc mcComment_initComment (bool onlySpaces);

/*
   addText - cs is a C string (null terminated) which contains comment text.
             This is appended to the comment, cd.
*/

extern "C" void mcComment_addText (mcComment_commentDesc cd, void * cs);

/*
   getContent - returns the content of comment, cd.
*/

extern "C" DynamicStrings_String mcComment_getContent (mcComment_commentDesc cd);

/*
   getCommentCharStar - returns the C string content of comment, cd.
*/

extern "C" void * mcComment_getCommentCharStar (mcComment_commentDesc cd);

/*
   setProcedureComment - changes the type of comment, cd, to a
                         procedure heading comment,
                         providing it has the procname as the first word.
*/

extern "C" void mcComment_setProcedureComment (mcComment_commentDesc cd, nameKey_Name procname);

/*
   getProcedureComment - returns the current procedure comment if available.
*/

extern "C" DynamicStrings_String mcComment_getProcedureComment (mcComment_commentDesc cd);

/*
   getAfterStatementComment - returns the current statement after comment if available.
*/

extern "C" DynamicStrings_String mcComment_getAfterStatementComment (mcComment_commentDesc cd);

/*
   getInbodyStatementComment - returns the current statement after comment if available.
*/

extern "C" DynamicStrings_String mcComment_getInbodyStatementComment (mcComment_commentDesc cd);

/*
   isProcedureComment - returns TRUE if, cd, is a procedure comment.
*/

extern "C" bool mcComment_isProcedureComment (mcComment_commentDesc cd);

/*
   isBodyComment - returns TRUE if, cd, is a body comment.
*/

extern "C" bool mcComment_isBodyComment (mcComment_commentDesc cd);

/*
   isAfterComment - returns TRUE if, cd, is an after comment.
*/

extern "C" bool mcComment_isAfterComment (mcComment_commentDesc cd);

/*
   Min - returns the lower of, a, and, b.
*/

static unsigned int Min (unsigned int a, unsigned int b);

/*
   RemoveNewlines -
*/

static DynamicStrings_String RemoveNewlines (DynamicStrings_String s);

/*
   seenProcedure - returns TRUE if the name, procName, appears as the first word
                   in the comment.
*/

static bool seenProcedure (mcComment_commentDesc__opaque cd, nameKey_Name procName);

/*
   dumpComment -
*/

static void dumpComment (mcComment_commentDesc__opaque cd);


/*
   Min - returns the lower of, a, and, b.
*/

static unsigned int Min (unsigned int a, unsigned int b)
{
  if (a < b)
    {
      return a;
    }
  else
    {
      return b;
    }
  /* static analysis guarentees a RETURN statement will be used before here.  */
  __builtin_unreachable ();
}


/*
   RemoveNewlines -
*/

static DynamicStrings_String RemoveNewlines (DynamicStrings_String s)
{
  while ((DynamicStrings_Length (s)) > 0)
    {
      if ((DynamicStrings_char (s, 0)) == ASCII_nl)
        {
          s = DynamicStrings_RemoveWhitePrefix (DynamicStrings_Slice (s, 1, 0));
        }
      else
        {
          return DynamicStrings_RemoveWhitePrefix (s);
        }
    }
  return s;
  /* static analysis guarentees a RETURN statement will be used before here.  */
  __builtin_unreachable ();
}


/*
   seenProcedure - returns TRUE if the name, procName, appears as the first word
                   in the comment.
*/

static bool seenProcedure (mcComment_commentDesc__opaque cd, nameKey_Name procName)
{
  DynamicStrings_String s;
  void * a;
  unsigned int i;
  unsigned int h;
  bool res;

  a = nameKey_keyToCharStar (procName);
  s = RemoveNewlines (cd->content);
  s = DynamicStrings_Slice (DynamicStrings_Mark (s), 0, static_cast<int> (Min (DynamicStrings_Length (s), nameKey_lengthKey (procName))));
  res = DynamicStrings_EqualCharStar (s, a);
  s = DynamicStrings_KillString (s);
  return res;
  /* static analysis guarentees a RETURN statement will be used before here.  */
  __builtin_unreachable ();
}


/*
   dumpComment -
*/

static void dumpComment (mcComment_commentDesc__opaque cd)
{
  libc_printf ((const char *) "comment : ", 10);
  switch (cd->type)
    {
      case mcComment_unknown:
        libc_printf ((const char *) "unknown", 7);
        break;

      case mcComment_procedureHeading:
        libc_printf ((const char *) "procedureheading", 16);
        break;

      case mcComment_inBody:
        libc_printf ((const char *) "inbody", 6);
        break;

      case mcComment_afterStatement:
        libc_printf ((const char *) "afterstatement", 14);
        break;


      default:
        CaseException ("../../gcc/m2/mc/mcComment.def", 20, 1);
        __builtin_unreachable ();
    }
  if (cd->used)
    {
      libc_printf ((const char *) " used", 5);
    }
  else
    {
      libc_printf ((const char *) " unused", 7);
    }
  libc_printf ((const char *) " contents = %s\\n", 16, DynamicStrings_string (cd->content));
}


/*
   initComment - the start of a new comment has been seen by the lexical analyser.
                 A new comment block is created and all addText contents are placed
                 in this block.  onlySpaces indicates whether we have only seen
                 spaces on this line.
*/

extern "C" mcComment_commentDesc mcComment_initComment (bool onlySpaces)
{
  mcComment_commentDesc__opaque cd;

  Storage_ALLOCATE ((void **) &cd, sizeof (mcComment__T1));
  mcDebug_assert (cd != NULL);
  if (onlySpaces)
    {
      cd->type = mcComment_inBody;
    }
  else
    {
      cd->type = mcComment_afterStatement;
    }
  cd->content = DynamicStrings_InitString ((const char *) "", 0);
  cd->procName = nameKey_NulName;
  cd->used = false;
  return static_cast<mcComment_commentDesc> (cd);
  /* static analysis guarentees a RETURN statement will be used before here.  */
  __builtin_unreachable ();
}


/*
   addText - cs is a C string (null terminated) which contains comment text.
             This is appended to the comment, cd.
*/

extern "C" void mcComment_addText (mcComment_commentDesc cd, void * cs)
{
  if (cd != NULL)
    {
      static_cast<mcComment_commentDesc__opaque> (cd)->content = DynamicStrings_ConCat (static_cast<mcComment_commentDesc__opaque> (cd)->content, DynamicStrings_InitStringCharStar (cs));
    }
}


/*
   getContent - returns the content of comment, cd.
*/

extern "C" DynamicStrings_String mcComment_getContent (mcComment_commentDesc cd)
{
  if (cd != NULL)
    {
      return static_cast<mcComment_commentDesc__opaque> (cd)->content;
    }
  return static_cast<DynamicStrings_String> (NULL);
  /* static analysis guarentees a RETURN statement will be used before here.  */
  __builtin_unreachable ();
}


/*
   getCommentCharStar - returns the C string content of comment, cd.
*/

extern "C" void * mcComment_getCommentCharStar (mcComment_commentDesc cd)
{
  DynamicStrings_String s;

  s = mcComment_getContent (cd);
  if (s == NULL)
    {
      return NULL;
    }
  else
    {
      return DynamicStrings_string (s);
    }
  /* static analysis guarentees a RETURN statement will be used before here.  */
  __builtin_unreachable ();
}


/*
   setProcedureComment - changes the type of comment, cd, to a
                         procedure heading comment,
                         providing it has the procname as the first word.
*/

extern "C" void mcComment_setProcedureComment (mcComment_commentDesc cd, nameKey_Name procname)
{
  if (cd != NULL)
    {
      if (seenProcedure (static_cast<mcComment_commentDesc__opaque> (cd), procname))
        {
          static_cast<mcComment_commentDesc__opaque> (cd)->type = mcComment_procedureHeading;
          static_cast<mcComment_commentDesc__opaque> (cd)->procName = procname;
        }
    }
}


/*
   getProcedureComment - returns the current procedure comment if available.
*/

extern "C" DynamicStrings_String mcComment_getProcedureComment (mcComment_commentDesc cd)
{
  if ((static_cast<mcComment_commentDesc__opaque> (cd)->type == mcComment_procedureHeading) && ! static_cast<mcComment_commentDesc__opaque> (cd)->used)
    {
      static_cast<mcComment_commentDesc__opaque> (cd)->used = true;
      return static_cast<mcComment_commentDesc__opaque> (cd)->content;
    }
  return static_cast<DynamicStrings_String> (NULL);
  /* static analysis guarentees a RETURN statement will be used before here.  */
  __builtin_unreachable ();
}


/*
   getAfterStatementComment - returns the current statement after comment if available.
*/

extern "C" DynamicStrings_String mcComment_getAfterStatementComment (mcComment_commentDesc cd)
{
  if ((static_cast<mcComment_commentDesc__opaque> (cd)->type == mcComment_afterStatement) && ! static_cast<mcComment_commentDesc__opaque> (cd)->used)
    {
      static_cast<mcComment_commentDesc__opaque> (cd)->used = true;
      return static_cast<mcComment_commentDesc__opaque> (cd)->content;
    }
  return static_cast<DynamicStrings_String> (NULL);
  /* static analysis guarentees a RETURN statement will be used before here.  */
  __builtin_unreachable ();
}


/*
   getInbodyStatementComment - returns the current statement after comment if available.
*/

extern "C" DynamicStrings_String mcComment_getInbodyStatementComment (mcComment_commentDesc cd)
{
  if ((static_cast<mcComment_commentDesc__opaque> (cd)->type == mcComment_inBody) && ! static_cast<mcComment_commentDesc__opaque> (cd)->used)
    {
      static_cast<mcComment_commentDesc__opaque> (cd)->used = true;
      return static_cast<mcComment_commentDesc__opaque> (cd)->content;
    }
  return static_cast<DynamicStrings_String> (NULL);
  /* static analysis guarentees a RETURN statement will be used before here.  */
  __builtin_unreachable ();
}


/*
   isProcedureComment - returns TRUE if, cd, is a procedure comment.
*/

extern "C" bool mcComment_isProcedureComment (mcComment_commentDesc cd)
{
  return (cd != NULL) && (static_cast<mcComment_commentDesc__opaque> (cd)->type == mcComment_procedureHeading);
  /* static analysis guarentees a RETURN statement will be used before here.  */
  __builtin_unreachable ();
}


/*
   isBodyComment - returns TRUE if, cd, is a body comment.
*/

extern "C" bool mcComment_isBodyComment (mcComment_commentDesc cd)
{
  return (cd != NULL) && (static_cast<mcComment_commentDesc__opaque> (cd)->type == mcComment_inBody);
  /* static analysis guarentees a RETURN statement will be used before here.  */
  __builtin_unreachable ();
}


/*
   isAfterComment - returns TRUE if, cd, is an after comment.
*/

extern "C" bool mcComment_isAfterComment (mcComment_commentDesc cd)
{
  return (cd != NULL) && (static_cast<mcComment_commentDesc__opaque> (cd)->type == mcComment_afterStatement);
  /* static analysis guarentees a RETURN statement will be used before here.  */
  __builtin_unreachable ();
}

extern "C" void _M2_mcComment_init (__attribute__((unused)) int argc, __attribute__((unused)) char *argv[], __attribute__((unused)) char *envp[])
{
}

extern "C" void _M2_mcComment_fini (__attribute__((unused)) int argc, __attribute__((unused)) char *argv[], __attribute__((unused)) char *envp[])
{
}