/* forkdll1.c (emx+gcc) */

/* Check copying of DLL data. */

#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <getopt.h>
#include <sys/types.h>
#include <sys/wait.h>
#include <emx/syscalls.h>

char *cleanup_msg;

void cleanup (void)
{
  fprintf (stderr, "Cleaning up %s...\n", cleanup_msg);
}


int main (int argc, char *argv[])
{
  int pid, c, st;
  char *s;
  FILE *f;

  if (_osmode != OS2_MODE)
    {
      /* Well, we can't reach this code anyway because DLLs do not
         work under DOS. */

      puts ("This program requires OS/2.");
      return 0;
    }

  if (argc != 2)
    {
      puts ("Usage: forkdll1 <filename>");
      return 1;
    }

  /* Let's modify some data in the CRT DLL's data segment: the
     _optind variable is in the CRT DLL. */

  _optind = 42;

  /* Let's modify some data in the CRT DLL's data segment: the environ
     variable is in the CRT DLL. */

  putenv ("FORKDLL1_ENV=Test string");

  /* Let's modify some data in the CRT DLL's data segment: the
     atexit() table is in the CRT DLL. */

  atexit (cleanup);
  cleanup_msg = "";

  /* Let's modify some data in the CRT DLL's data segment: the streams
     table (_streamv) is in the CRT DLL. */

  f = fopen (argv[1], "r");
  if (f == NULL)
    {
      perror (argv[1]);
      return 2;
    }

  /* Fork.  The child process should receive the open stream. */

  pid = fork ();
  if (pid == 0)
    {
      /* Child. */

      s = getenv ("FORKDLL1_ENV");
      if (_optind != 42 || s == NULL || strcmp (s, "Test string") != 0)
        {
          /* If _optind hasn't been copied, streams and low-level I/O
             probably won't work.  Use a syscall to print the
             message. */

          static char msg[] = "DLL data not copied\r\n";
          __write (2, msg, sizeof (msg) - 1);
          _exit (2);
        }

      /* Copy the file to stdout. */

      cleanup_msg = "child";
      while ((c = fgetc (f)) != EOF)
        if (putchar (c) == EOF)
          {
            perror ("<stdout>");
            return 2;
          }
      if (ferror (f) || fclose (f) != 0)
        {
          perror (argv[1]);
          return 2;
        }
      return 0;
    }
  else if (pid == -1)
    {
      perror ("fork()");
      return 2;
    }
  else
    {
      /* Parent.  Wait for termination of the child process. */

      cleanup_msg = "parent";
      fclose (f);
      if (waitpid (pid, &st, 0) == -1)
        {
          perror ("waitpid()");
          return 2;
        }
      if (WIFEXITED (st))
        return WEXITSTATUS (st);
      puts ("Child process did not terminate normally.");
      return 2;
    }
}
