/* This testcase is part of GDB, the GNU debugger.

   Copyright 2008-2021 Free Software Foundation, Inc.

   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; 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, see <http://www.gnu.org/licenses/>.  */

#include <string.h>

struct s
{
  int a;
  int *b;
};

struct ss
{
  struct s a;
  struct s b;
};

struct arraystruct
{
  int y;
  struct s x[2];
};

struct ns {
  const char *null_str;
  int length;
};

struct lazystring {
  const char *lazy_str;
  /* If -1, don't pass length to gdb.lazy_string().  */
  int len;
};

struct hint_error {
  int x;
};

struct children_as_list {
  int x;
};

#ifdef __cplusplus
struct S : public s {
  int zs;
};

struct SS {
  int zss;
  S s;
};

struct SSS
{
  SSS (int x, const S& r);
  int a;
  const S &b;
};
SSS::SSS (int x, const S& r) : a(x), b(r) { }

class VirtualTest 
{ 
 private: 
  int value; 

 public: 
  VirtualTest () 
    { 
      value = 1;
    } 
};

class Vbase1 : public virtual VirtualTest { };
class Vbase2 : public virtual VirtualTest { };
class Vbase3 : public virtual VirtualTest { };

class Derived : public Vbase1, public Vbase2, public Vbase3
{ 
 private: 
  int value; 
  
 public:
  Derived () 
    { 
      value = 2; 
    }
};

class Fake
{
  int sname;
  
 public:
  Fake (const int name = 0):
  sname (name)
  {
  }
};
#endif

struct to_string_returns_value_inner
{
  int val;
};

struct to_string_returns_value_wrapper
{
  struct to_string_returns_value_inner inner;
};

struct substruct {
  int a;
  int b;
};

struct outerstruct {
  struct substruct s;
  int x;
};

struct outerstruct
substruct_test (void)
{
  struct outerstruct outer;
  outer.s.a = 0;
  outer.s.b = 0;
  outer.x = 0;

  outer.s.a = 3;		/* MI outer breakpoint here */

  return outer;  
}

typedef struct string_repr
{
  struct whybother
  {
    const char *contents;
  } whybother;
} string;

/* This lets us avoid malloc.  */
int array[100];
int narray[10];

struct justchildren
{
  int len;
  int *elements;
};

typedef struct justchildren nostring_type;

struct memory_error
{
  const char *s;
};

struct container
{
  string name;
  int len;
  int *elements;
  int is_map_p;
  int is_array_p;
};

typedef struct container zzz_type;

string
make_string (const char *s)
{
  string result;
  result.whybother.contents = s;
  return result;
}

zzz_type
make_container (const char *s)
{
  zzz_type result;

  result.name = make_string (s);
  result.len = 0;
  result.elements = 0;
  result.is_map_p = 0;
  result.is_array_p = 0;

  return result;
}

void
add_item (zzz_type *c, int val)
{
  if (c->len == 0)
    c->elements = array;
  c->elements[c->len] = val;
  ++c->len;
}

void
set_item(zzz_type *c, int i, int val)
{
  if (i < c->len)
    c->elements[i] = val;
}

void init_s(struct s *s, int a)
{
  s->a = a;
  s->b = &s->a;
}

void init_ss(struct ss *s, int a, int b)
{
  init_s(&s->a, a);
  init_s(&s->b, b);
}

void do_nothing(void)
{
  int c;

  c = 23;			/* Another MI breakpoint */
}

struct nullstr
{
  char *s;
};

struct string_repr string_1 = { { "one" } };
struct string_repr string_2 = { { "two" } };

int
eval_func (int p1, int p2, int p3, int p4, int p5, int p6, int p7, int p8)
{
  return p1;
}

static void
eval_sub (void)
{
  struct eval_type_s { int x; } eval1 = { 1 }, eval2 = { 2 }, eval3 = { 3 },
				eval4 = { 4 }, eval5 = { 5 }, eval6 = { 6 },
				eval7 = { 7 }, eval8 = { 8 }, eval9 = { 9 };

  eval1.x++; /* eval-break */
}

static void
bug_14741()
{
  zzz_type c = make_container ("bug_14741");
  add_item (&c, 71);
  set_item(&c, 0, 42); /* breakpoint bug 14741 */
  set_item(&c, 0, 5);
}

/* Some typedefs/variables for checking that GDB doesn't lose typedefs
   when looking for a printer.  */
typedef int int_type;
typedef int_type int_type2;
typedef int_type int_type3;

int an_int = -1;
int_type an_int_type = 1;
int_type2 an_int_type2 = 2;
int_type3 an_int_type3 = 3;

int
main ()
{
  struct ss  ss;
  struct ss  ssa[2];
  struct arraystruct arraystruct;
  string x = make_string ("this is x");
  zzz_type c = make_container ("container");
  zzz_type c2 = make_container ("container2");
  const struct string_repr cstring = { { "const string" } };
  /* Clearing by being `static' could invoke an other GDB C++ bug.  */
  struct nullstr nullstr;
  nostring_type nstype, nstype2;
  struct memory_error me;
  struct ns ns, ns2;
  struct lazystring estring, estring2, estring3;
  struct hint_error hint_error;
  struct children_as_list children_as_list;
  struct to_string_returns_value_wrapper tsrvw = { { 1989 } };

  nstype.elements = narray;
  nstype.len = 0;

  me.s = "blah";

  init_ss(&ss, 1, 2);
  init_ss(ssa+0, 3, 4);
  init_ss(ssa+1, 5, 6);
  memset (&nullstr, 0, sizeof nullstr);

  arraystruct.y = 7;
  init_s (&arraystruct.x[0], 23);
  init_s (&arraystruct.x[1], 24);

  ns.null_str = "embedded\0null\0string";
  ns.length = 20;

  /* Make a "corrupted" string.  */
  ns2.null_str = NULL;
  ns2.length = 20;

  estring.lazy_str = "embedded x\201\202\203\204";
  estring.len = -1;

  /* Incomplete UTF-8, but ok Latin-1.  */
  estring2.lazy_str = "embedded x\302";
  estring2.len = -1;

  estring3.lazy_str = NULL;
  estring3.len = 42;

#ifdef __cplusplus
  S cps;

  cps.zs = 7;
  init_s(&cps, 8);

  SS cpss;
  cpss.zss = 9;
  init_s(&cpss.s, 10);

  SS cpssa[2];
  cpssa[0].zss = 11;
  init_s(&cpssa[0].s, 12);
  cpssa[1].zss = 13;
  init_s(&cpssa[1].s, 14);

  SSS sss(15, cps);

  SSS& ref (sss);

  Derived derived;
  
  Fake fake (42);
#endif

  add_item (&c, 23);		/* MI breakpoint here */
  add_item (&c, 72);

#ifdef MI
  add_item (&c, 1011);
  c.elements[0] = 1023;
  c.elements[0] = 2323;

  add_item (&c2, 2222);
  add_item (&c2, 3333);

  substruct_test ();
  do_nothing ();
#endif

  nstype.elements[0] = 7;
  nstype.elements[1] = 42;
  nstype.len = 2;
  
  nstype2 = nstype;

  eval_sub ();

  bug_14741();      /* break to inspect struct and union */
  return 0;
}
