/* stupid test program
 *
 *   It only prints stupid lines in a stupid file descriptor.
 *
 *   To exit press CTRL+C o kill it.
 *
 *   If you want to get a stacktrace at termination moment,
 *   call this program in this way:
 *
 *     LD_PRELOAD=./stacktrace ./test [arguments]
 *
 *   Or link it statically against libstacktrace.a (use the
 *   LINKED_STACKTRACE definition to enable library
 *   initialization).
 */

#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/time.h>
#include <sys/resource.h>
#include <unistd.h>

#ifdef LINKED_STACKTRACE
#include "stacktrace.h"
#endif

#define NEW_SS  (12)
#define EAT_SS  1250

void call_the_stack_consumer(int argc, char **argv, int x, void (*func)(int, char **));
void call_the_slow_function(int argc, char **argv);
void call_the_boring_function(int argc, char **argv);
void call_the_really_slow_echo_function(int argc, char **argv);
void call_the_echo_performer(int argc, char **argv);

void call_the_echo_performer(int argc, char **argv)
{
  if(argc > 1)
  {
    call_the_echo_performer(argc - 1, argv);
    printf("    You saiiiiiiiiiiiidd %s\n", argv[argc - 1]);
    sleep(1);
  }
}

void call_the_really_slow_echo_function(int argc, char **argv)
{
  call_the_stack_consumer(argc, argv, EAT_SS, call_the_echo_performer);
  call_the_stack_consumer(argc, argv, EAT_SS, call_the_boring_function);
}

void call_the_stack_consumer(int argc, char **argv, int x, void (*func)(int, char **))
{
  if(x > 0)
    call_the_stack_consumer(argc, argv, x-1, func);
  else
    func(argc, argv);
}

void call_the_slow_function(int argc, char **argv)
{
  int i;

  printf("I am so\n");
  for(i = 0; i < 5; i++)
  {
    sleep(1);
    printf("      ...so\n");
  }
  sleep(1);
  printf("        ...slooooow.\n");
  sleep(1);

  call_the_stack_consumer(argc, argv, EAT_SS, call_the_really_slow_echo_function);
}

void call_the_boring_function(int argc, char **argv)
{
  printf("I am boring!\n");

  call_the_stack_consumer(argc, argv, EAT_SS, call_the_slow_function);
}

int main(int argc, char **argv)
{
  struct rlimit rlim;

#ifdef LINKED_STACKTRACE
  stacktrace_init(1);
#endif
  if(argc < 2)
    printf("This program is even funnier if it is invoked with parameters.\n");

  if(getrlimit(RLIMIT_STACK, &rlim) < 0) perror("getrlimit()");
  printf("current stack size %ld (setting to %d)\n", rlim.rlim_cur, NEW_SS);
  rlim.rlim_cur = NEW_SS;
  rlim.rlim_max = NEW_SS;
  if(setrlimit(RLIMIT_STACK, &rlim) < 0) perror("setrlimit()");

  call_the_boring_function(argc, argv);

  exit(0);
}
