/* mapit: take diplomacy history, e.g. from judge, and create a map */
/* George Boyce, 92.08.25 */
/* David Kovar, 92.11.25 */
/* Richard Nash, 93.01.22 */

/* I was unable to contact George Boyce so I took over maintenance of the
   program. It's still his code, I just cleaned it up, wrote a makefile,
   wrote a README file, and cleaned the code up a bit. If you improve it,
   please let me know: kovar@world.std.com
*/

/*
  this program is in the public domain, if you improve it, please let me know
  grb1@cornell.edu

  map information may be copyright by the original author
  check the individual aux files for more information
*/

/* History:

   92.08.25 - George Boyce -   developed.
   92.11.17 - David C. Kovar - Added README and makefile.
                             - Cleaned code up for portability.
                             - Changed to version 1.3.
   92.12.01 - David C. Kovar - Fixed some casts to make gcc happy.
                             - Added strdup.c to package for systems
                               that do not have it.
                             - Changed version to 1.4
   93.01.20 - David C. Kovar - Fixed code to handle Off Board C correctly.
                             - Changed version to 1.5
   93.01.22 - Richard Nash   - Added code to make output comment complient
   93.10.15 - Kent Irwin     - Fixed several bugs, improved portability
                             - added getopt.c to package for systems that
                               do not have it.
                             - added strrstr.c to package for systems that do
                               not have it.
                             - added #ifdef code for compiling on Macintosh
                               Symantec Think C.
                             - moved command line args -y,-l,-c, and -z from
                               the Unix to the C code.
                             - changed version to 1.6
   93.10.29 - David C. Kovar - Fixed a bug with the OBC detection.
                             - Wrapped some lines in #ifdef ANSI
   93.11.05 - Kent Irwin     - Fixed a bug with OBH.
                             - Changed to version 1.7
   93.12.03 - David C. Kovar - Fixed bug with ", NO ORDER PROCESSED (DISBAND)"
                             - Added Thierry Cornu's aberration maps
                             - Changed to version 1.8
   94.02.07 - David C. Kovar - Tuned things for aberration.
   94.02.22 - David C. Kovar - Removed case where mapit was free()ing
                               previously free()'d pointers.
                             - Improved the makefile.
   94.02.23 - David C. Kovar - Corrected two errors in aberration.info.
   94.02.23 - Christopher Davis - Added two options for printing to dipmap
   94.03.10 - David C. Kovar - Fixed error in handling of waived adjustments.
   94.xx.xx - Various        - Added -p, -v, -n options for doing things with
                               postscript.
              Larry Richardson - Fixed aberration maps.
   94.04.23 - Thomas Widmann - Added -b option for making new borders.
   94.05.15 - Thierry Cornu  - Color chaos and Milan maps
   94.06.18 - Martin Protzen - fixed bug related to disappearing units after
                               disbands & added Switzerland to *.info files.
   94.06.23 - C. Marcus, Jr. - Added Chromatic, Britain, & Pure maps; changed
                               dipmap script to handle unlimited variants
                               without needing a separate switch for each;
                               backed out some Aberration changes that caused
                               that variant to fail on some printers
   94.07.11 - C.McLoughlin   - Interpret the message after a retreat order
                                and show it on the map.
   94.08.11 - F.Riepenhausen - Fixed problem matching STP/NC with STP.
   96.08.17 - GEM            - Fixed country ownership problem.
   96.10.21 - Darren Capel   - Fixed parsing of long country names.
   97.xx.xx - Manus Hand MJH - added coloured supply centers with special map
       Note that this version of mapit **ONLY** works with "Manusified"
       .cmap.ps files. Otherwise it produces faulty PS-files.
   98.02.20 - Thomas Kuhlmann (TKU) - Added automatic detection of cmap.ps
                                      with coloured supply center commands.
                              - force uncolored SCs with -u option
*/
/* How to compile for macintosh:
    - Use Symantec Think C
    - Link in MacTraps library
    - define: MACINTOSH, STRDUP_MISSING, GETOPT_MISSING, STDC_HEADERS,
                  STRRSTR_MISSING in every source file
*/

#define VERSION "This is version 1.15"

/* there are two external files: */

#define DEFAULT_INFO "mapit.info"
/*
  MAPINFO (mapit.info) is a list of sites of the form:
  xpos ypos |nickname|owner country|full name[|nick2|nick3|...]

  From that we create an internal data structure which maps the full name
  used in judge reports to short names used on the map and the coordinates for
  drawing arrows etc.

*/

#define DEFAULT_PS "mapit.ps"
/*
  MAPPS (mapit.ps) is the majority of the postscript. It should provide the
  following functions:

  DrawMap    draws the base map

  xpos ypos (string) DrawName
             labels the specified province

  country1,country2, ... countryN
             These functions set the colors etc to be used when drawing units.

  xpos ypos DrawArmy
  xpos ypos DrawFleet
             These functions draw the a given unit at a given location

  OrderReport,RetreatReport,OwnerReport,AdjustReport,StatusReport
             These functions prepare us to write various reports

  (string) WriteOrder,WriteRetreat,WriteOwner,WriteAdjust,WriteStatus
             These functions actually write a specified report line

  x1 y1 x2 y2 ArrowMove
  x1 y1 x2 y2 ArrowHold
  x1 y1 x2 y2 x3 y3 ArrowSupport
  x1 y1 x2 y2 x3 y3 ArrowConvoy
             These functions draw arrows indicating the specified order

  ShowPage   final postscript commands to display the current map
*/

/*
  to do:

  parse:
  "The following units were dislodged:"
  "The Russian Army in Outer Mongolia with no valid retreats was destroyed."
  "The Chinese Army in Manchuria can retreat to Outer Mongolia."

  fix moveto() to detect foo - foo-bar

  fix parse_status to handle retreat with mutilple alternate destinations
*/
#ifdef MACINTOSH
#include <stdlib.h>
#include <console.h>
#include <Files.h>
#endif

#ifdef STRDUP_MISSING
#ifdef ANSI
char *strdup (char *s1);
#else
char *strdup ();
#endif
#endif

#ifdef STRRSTR_MISSING
#ifdef ANSI
char *strrstr (char *s1, char *s2);
#else
char *strrstr ();
#endif
#endif

#include <stdio.h>
#include <string.h>
#include <ctype.h>

extern char *strstr ();


#define MIN(x,y) (x<y?x:y)

#define MAXNAMES 500
struct
  {
    char *name;                 /* full name of province */
    char *nick;                 /* official nickname */
    char *owner;                /* owner of province */
    char *nicks;                /* list of alternate nicknames */
    int x, y;                   /* x and y coordinates */
/*    int in_ps;                   nick found in PSmap for colored supplies TKU */
/*  deleted, because not all provinces have supply center */
  }
map[MAXNAMES];
int mapcount;

#define MAXUNITS 100
struct unitstruct
  {                             /* keeps track of new unit positions */
    char *country;              /* owning country */
    char type;                  /* 'A' or 'F' */
    int loc;                    /* index into map struct of current location */
  }
units[MAXUNITS];
int unitcount;

#define MAXNATIONS 50
char *nation[MAXNATIONS];
int nationcount;
int nation_in_ps[MAXNATIONS];

/* Some variables for the -b option. */
int new_borders = 0;            /* 1: Make new borders, 0: Don't. */
FILE *nstdout;                  /* Temporary file */
int ownerlist[MAXNAMES];        /* We need an owner for each country */
char tempfilename[L_tmpnam];    /* Temporary filename */
char *country1, *country2;
int ownernum;

char *info_file, *ps_file;
/* ADDED BY MJH */
static char buffer[BUFSIZ] = "";
static enum { UNCOLORED_SC, COLORED_SC, AUTODETECT }
    colored_supplies = AUTODETECT;  /* flag for colored supplies TKU */

main (argc, argv)
     int argc;
     char **argv;
{
  /* input line, current season, year, and game name */
  char line[BUFSIZ], copy[BUFSIZ], season[BUFSIZ], name[BUFSIZ];
  int year;
  char title[BUFSIZ];           /* map title from above info */
  char deftitle[BUFSIZ];        /* default title from command line */
  char message[BUFSIZ];         /* message from "deadline" line */
  char defmsg[BUFSIZ];          /* default message from command line */
  int usemsg, usetitle;         /* true if we should use the command line value */
  int onlystatus;               /* true is we want only the status map */
  int i, j, k;                  /* misc counters */
  char *p0, *p1;                /* and character pointers */
  int started;                  /* is a map already started? */
  int report;                   /* type of report */

  extern char *optarg;          /* used by getopt() */
  extern int optind;
  int c;
  int do_new_map = 1;           /* print a new map at end of run */

#ifdef MACINTOSH
  /* Two variables needed to reset the default folder for Macintosh */
  Str255 volName;
  short vRef;
#endif

/*
  int malloc_debug();
  int malloc_verify();

  malloc_debug(2);
*/
  nstdout = stdout;

  fprintf (stderr, "Diplomacy map program, %s\n", VERSION);

  defmsg[0] = '\0';
  usemsg = 0;
  onlystatus = 0;
  strcpy (deftitle, "(game start)");
  usetitle = 0;
  info_file = (char *) NULL;
  ps_file = (char *) NULL;      /* no data files specified yet */

  for (i = 0; i < MAXNAMES; ++i)
    ownerlist[i] = -1;          /* A little init for the -b option */

#ifdef MACINTOSH
  /* Now call the routines to handle command line arguments and I/O redirection */
  /* First get the default folder.  This will have to be restored after
           ccommand() is called.  Ccommand() changes the default folder. */
  GetVol (volName, &vRef);
  /* Get the command line */
  argc = ccommand (&argv);
  /* Restore the default folder */
  SetVol (volName, vRef);
#endif


  while ((c = getopt (argc, argv, "ui:M:m:n :T:t:p:s :b :y :l :c :z ")) != -1)
    switch (c)
      {
      case 'u':         /* -u force uncolored supply centers */
        colored_supplies = UNCOLORED_SC;
      break;
      case 'i':         /* -i info_file */
        info_file = (char *) strdup (optarg);
        break;
      case 'M':         /* -M message (always use this message) */
        ++usemsg;
      case 'm':         /* -m message (default message) */
        strcpy (defmsg, optarg);
        break;
      case 'n':         /* -n (do not print new map at end) */
        do_new_map = 0;
        break;
      case 's':         /* -s (print only the status map) */
        onlystatus = 1;
        break;
      case 'b':
        new_borders = 1;        /* Yes, we want new borders */
        break;
      case 'T':         /* -T title (always use this title) */
        ++usetitle;
      case 't':         /* -t title (default title) */
        strcpy (deftitle, optarg);
        break;
      case 'p':         /* -p map_ps_file */
        ps_file = (char *) strdup (optarg);
        break;
      case 'y':         /* youngstown map wanted */
        info_file = "youngstown.info";
        ps_file = "youngstown.map.ps";
        break;
      case 'l':         /* loeb9 map wanted     */
        ps_file = "loeb9.map.ps";
        info_file = "loeb9.info";
        break;
      case 'c':         /* crowded map wanted */
        ps_file = "crowded.map.ps";
        info_file = "crowded.info";
        break;
      case 'z':         /* chaos map wanted */
        ps_file = "chaos.map.ps";
        info_file = "chaos.info";
        break;
      case '?':         /* error */
        exit (1);
      }

  if (new_borders)
    {                           /* We'll need a temporary file */
      tmpnam (tempfilename);
      if (!(nstdout = fopen (tempfilename, "w")))
        fprintf (stderr, "Unable to open file..\n");
    }

  if (init ())
    {
      fprintf (stderr, "main: unable to initialize\n");
      exit (1);
    }

  fprintf (stderr, "main: looking for report(s)...\n");
  started = 0;

  /* scan history until we see a start line and then process that section */
  title[0] = '\0';              /* don't know the title of the map yet */
  message[0] = '\0';            /* and no deadline message seen */
  while (gets (line))
    {
      if (line[0] == '\0' || line[0] == ' ' || line[0] == '\t')
        continue;               /* skip blank and comment lines */

      copyline (copy, line);    /* make an uppercase copy of the line */
#define MOVE1   "MOVEMENT RESULTS"
#define MOVE2   "MOVEMENT ORDERS"       /* not used */
#define ADJUST  "ADJUSTMENT ORDERS"
#define RETREAT "RETREAT ORDERS"
#define START   "STARTING POSITION"

#define STATUS   "STATUS OF THE "
#define PHASEM   "MOVEMENT PHASE"
#define PHASEA   "ADJUSTMENT PHASE"
#define PHASER   "RETREAT PHASE"

#define M 1
#define A 2
#define R 3
#define S 4
#define SM 5
#define SA 6
#define SR 7


#define DEADLINE "HAS A DEADLINE OF"
/*
    if (strstr(copy,DEADLINE) != NULL) {
      strcpy(message,line);
      continue;
    }
*/
      if (strncmp (copy, MOVE1, strlen (MOVE1)) == 0)
        {
          i = strlen (MOVE1);
          report = M;
        }
      else if (strncmp (copy, ADJUST, strlen (ADJUST)) == 0)
        {
          i = strlen (ADJUST);
          report = A;
        }
      else if (strncmp (copy, RETREAT, strlen (RETREAT)) == 0)
        {
          i = strlen (RETREAT);
          report = R;
        }
      else if (strncmp (copy, START, strlen (START)) == 0)
        {
          i = strlen (START);
          report = S;
        }
      else if (strncmp (copy, STATUS, strlen (STATUS)) == 0)
        {
          i = strlen (STATUS);
          if (strncmp (&copy[i], PHASEM, strlen (PHASEM)) == 0)
            {
              i += strlen (PHASEM);
              report = SM;
            }
          else if (strncmp (&copy[i], PHASEA, strlen (PHASEA)) == 0)
            {
              i += strlen (PHASEA);
              report = SA;
            }
          else if (strncmp (&copy[i], PHASER, strlen (PHASER)) == 0)
            {
              i += strlen (PHASER);
              report = SR;
            }
          else
            continue;
        }
      else
        continue;

      /* ok, got a start line. See if it is a judge line... */
      j = sscanf (&line[i], " for %s of %d. (%[^.])", season, &year, name);
	  /* or a DPjudge line (MJH) */
	  if (j != 3)
      	j = sscanf (&line[i], " for %s %d. (%[^.])", season, &year, name);
      if (j == 3)               /* yup, create title from it */
        sprintf (title, "%s, %s %d", name, season, year);
      else
        {
          season[0] = '\0';
          strcpy (title, deftitle);
        }

      /* maybe override the title and message found in report */
      if (usetitle)
        strcpy (title, deftitle);
      if (usemsg || message[0] == '\0') /* */
        strcpy (message, defmsg);

      /* display progress */
      fprintf (stderr, "main: found: %s\n", line);

      /* parse this section of the file */
      switch (report)
        {
        case M:         /* movement */
          if (started)
            {                   /* done with previous map */
              if (!onlystatus)
/* BRACES AND FIRST STATEMENT BELOW ADDED BY MJH */
                {
                  if (colored_supplies)  /* conditional output by TKU */
                      fprintf (nstdout, "closepath newpath\n%s\nBlack\n", buffer);
                  fprintf (nstdout, "ShowPage\n");      /* so eject it, */
                }
              else
                fprintf (nstdout, "erasepage\n");       /* or not, as requested */
              EndPage ();
            }
          StartPage ();
          drawmap (title, message);     /* draw an empty map */
          parse_movement ();
          started = 2;          /* started and orders processed */
          break;
        case A:         /* adjustment */
          if (!started)
            {                   /* we are probably already drawing a map */
              StartPage ();
              drawmap (title, message); /* but if not, draw an empty map */
            }
          parse_adjustment ();
          ++started;            /* more orders processed */
          break;
        case R:         /* retreat */
          if (!started)
            {                   /* we are probably already drawing a map */
              StartPage ();
              drawmap (title, message); /* but if not, draw an empty map */
            }
          parse_retreat ();
          ++started;            /* more order processed */
          break;
        case SM:                /* status of movement phase */
        case SA:                /* status of adjustment phase */
        case SR:                /* status of retreat phase */
        case S:         /* start postions */
          if (started)
            {                   /* we are probably just starting */
              if (!onlystatus)
/* BRACES AND FIRST STATEMENT BELOW ADDED BY MJH */
                {
                  if (colored_supplies)  /* conditional output by TKU */
                      fprintf (nstdout, "closepath newpath\n%s\nBlack\n", buffer);
                  fprintf (nstdout, "ShowPage\n");
                }
              else
                fprintf (nstdout, "erasepage\n");
              EndPage ();
            }
          StartPage ();
          drawmap (title, message);     /* draw an empty map */
          parse_start (report); /* parse setup */
          if (onlystatus)
            {                   /* all done? */
/* ADDED BY MJH */
                   if (colored_supplies)  /* conditional output by TKU */
                  fprintf (nstdout, "closepath newpath\n%s\nBlack\n", buffer);
              fprintf (nstdout, "ShowPage\n");
              exit (0);
            }
          started = 1;          /* map started but units are in final position */
          break;
        }

      /* forget whatever title/message we have seen */
      message[0] = '\0';
      title[0] = '\0';
    }

  if (!started)
    fprintf (stderr, "main: no reports found, nothing to map\n");
  else
    {
      if (!onlystatus)
        {
/* BRACES AND FIRST STATEMENT BELOW ADDED BY MJH */
          if (colored_supplies)  /* conditional output by TKU */
              fprintf (nstdout, "closepath newpath\n%s\nBlack\n", buffer);
          fprintf (nstdout, "ShowPage\n");
        }
      else
/* BRACES AND FIRST STATEMENT BELOW ADDED BY MJH */
        {
          if (colored_supplies)  /* conditional output by TKU */
             fprintf (nstdout, "closepath newpath\n%s\nBlack\n", buffer);
          fprintf (nstdout, "erasepage\n");
        }
      EndPage ();
    }
  if (started > 1 && do_new_map)
    {

      /* before we leave, draw a new map showing upated positions... */
      if (strcmp (season, "Fall") == 0)
        strcpy (season, "Winter");
      else if (strcmp (season, "Spring") == 0)
        strcpy (season, "Fall");
      else if (strcmp (season, "Winter") == 0)
        {
          strcpy (season, "Spring");
          ++year;
        }
      if (season[0])
        sprintf (title, "%s, %s %d", name, season, year);
      else
        strcpy (title, deftitle);
      StartPage ();
      drawmap (title, message); /* draw an empty map */
      drawnew ();               /* draw map with updated positions  */
/* ADDED BY MJH */
           if (colored_supplies)  /* conditional output by TKU */
          fprintf (nstdout, "closepath newpath\n%s\nBlack\n", buffer);
      fprintf (nstdout, "ShowPage\n");  /* eject it */
      EndPage ();
    }
  EndDocument ();

  /* Now we'll do some -b work */
  if (new_borders)
    {
      fclose (nstdout);

      for (i = 0; i <= mapcount; ++i)
        if (strcmp (map[i].owner, "---"))       /* Owner exists */
          if (ownerlist[countrynum (map[i].nick)] == -1)
            ownerlist[countrynum (map[i].nick)] = ownerlist[countrynum (map[i].owner)];

      /* Handle multiple coasts */
      for (i = 0; i < mapcount; ++i)
        if (countrynum (map[i].nick) == countrynum (map[i + 1].nick))
          if (ownerlist[i + 1] > ownerlist[i])
            ownerlist[i] = ownerlist[i + 1];
          else
            ownerlist[i + 1] = ownerlist[i];

      if (!(nstdout = fopen (tempfilename, "r")))
        fprintf (stderr, "Unable to reopen file.\n");
      else
        {
          while (fgets (line, BUFSIZ, nstdout))
            if (strstr (line, "%^") == NULL)
              printf ("%s", line);
            else
              {                 /* Country border in PostScript */
                country1 = strstr (line, "%^") + 2;
                *(country1 + 3) = '\0';
                country2 = country1 + 4;
                *(country2 + 3) = '\0';
                if (same_owner (country1, country2)
                    && (ownerlist[countrynum (country1)] != -1))
                  printf ("internal\n");
                else
                  printf ("BORDER\n");
              }
          fclose (nstdout);
          remove (tempfilename);
        }
    }
}


/*
  MOVEMENT RESULTS

  [country:] unit location order. [(*failure code*)]

  where "order" is one of the following:

  move_order    ["->" | "-" | "MOVE" | "M"] [location move_order] location
  hold_order    ["HOLD" | "H"]
  support_hold  ["SUPPORT" | "S"] [nation] unit location
  support_move  ["SUPPORT" | "S"] [nation] unit location move_order
  convoy        ["CONVOY" | "C"] [nation] army location ["->" | "-"] location
  nmr           [", NO ORDER PROCESSED" | "NMR" | "NO MOVE RECEIVED"]

  unit          army | fleet
  army          "A" | "ARMY"
  fleet         "F" | "FLEET"

  location      nick | full_name
*/
parse_movement ()
{
  char line[BUFSIZ];            /* the current order being processed */
  char copy[BUFSIZ];            /* a temp copy */
  char *p0, *p1, *p2, *p3;      /* some char pointers */
  int i, j, k;                  /* misc counters */

  char country[BUFSIZ];
  char unit;                    /* unit type, "A" or "F" */
  int order;                    /* one of the following: */
  int si, di, di2;              /* index of source and destination location(s) */
  /* (convoy and support can have two dests) */

#define UNKNOWN 0
#define SUPPORT 1
#define CONVOY 2
#define HOLD 3
#define MOVE 4
#define NMR 5

#define MAXORDERS MAXUNITS
  char *orders[MAXORDERS];      /* orders to write to the left of the map */
  char new[BUFSIZ];             /* current order being formed */
  int ordernum;                 /* count of orders */
  char *graphics[MAXORDERS];    /* representation of orders on the map */
  char newg[BUFSIZ];            /* current graphic being formed */
  int graphicnum;               /* count of graphics */

  char *msg;                    /* current bouce/cut message */
  int fail;                     /* flag to indicate success of order */
  int x, y;                     /* map coordinate of support/convoy arrow */

  int error;                    /* true if a syntax (or malloc) error */

  for (i = 0; i < unitcount; ++i)
    {
      if (free (units[i].country) == 0)
        ;
    }
  unitcount = 0;

  strcpy (country, "unknown");
  ordernum = 0;
  graphicnum = 0;
  error = 0;
  while (gets (line))
    {
      if (line[0] == '\0' || line[0] == ' ' || line[0] == '\t')
        continue;               /* skip blank and comment lines */

      new[0] = '\0';
      newg[0] = '\0';

      copyline (copy, line);    /* first make a copy of it */

      if (strncmp (copy, "THE FOLLOWING", 13) == 0
/* MJH */
	  ||  strstr (copy, "NO VALID") != NULL
	  ||  strstr (copy, "DESTROYED") != NULL
/* END MJH */
/* MORE MJH */
	  ||  strstr (copy, "INCOME HAS BEEN DISTRIBUTED") != NULL)
/* END MORE MJH */
        continue;

      /* see if we are at the end of this section... */
      if (strncmp (copy, "THE ", 4) == 0 ||     /* The next phase of .... */
          strncmp (copy, "ORDERS ", 7) == 0 ||  /* Orders not received... */
          strncmp (copy, "END", 3) == 0)        /* non judge standard */
        break;                  /* end of movement results */
      if (strncmp (copy, "OWNERSHIP ", 10) == 0)
        {                       /* Ownership of supply centers: */
          /* end of movement results, and start of fall report */
          parse_fall_report ();
          break;
        }

      /* still here, parse the line... */

      /* is the first/only token a country specifier? */
      p1 = strpbrk (copy, ": ");
      if (p1 == NULL || *p1 == ':')
        {                       /* yes, this is a country tag */
          if (p1 != NULL)
            *(p1++) = '\0';     /* zap the colon */
          p0 = copy;

          if (strcmp (p0, country))
            {
              strcpy (country, p0);     /* start new country */
              fprintf (nstdout, "%s\n", country);
              orders[ordernum] = (char *) strdup (country);
              string_check (orders[ordernum], 1);
              ++ordernum;
            }                   /* otherwise just continue on */
        }
      else
        p1 = copy;              /* no, token is not a country tag */

      if (p1 == NULL || *p1 == '\0')
        continue;               /* nothing else on this line */

      /* p0 maybe points to country, p1 points to next token */
      error = 1;                /* if we exit now, it is because of an error */

      /* next token is the unit type... */
      if (*p1 == ' ')
        ++p1;
      unit = *p1;

      /* find next token, a location name */
      p0 = (strchr (p1, ' '));
      if (string_check (p0, 0))
        break;
      ++p0;

      /* try to read order type, p0 pointing to unit location name */

      /* first remove any message from the end of the line */
      /* anything between two stars is the message */
      msg = "";
      fail = 0;
      if ((p2 = strstr (p0, " (*")) != NULL)
        {
          p1 = strstr (p2, "*)");
          if (p1 != NULL)
            *p1 = '\0';
          else
            {
              fprintf (stderr, "movement: expected command (*message*)\n");
              break;
            }
          *p2 = '\0';
          msg = p2 + 3;
          fail = 1;
        }

      order = UNKNOWN;
      /* test for support first since we can support hold/convoy/move */
      if ((p1 = strstr (p0, " SUPPORT")) ||     /* or SUPPORTS */
          (p1 = strstr (p0, " S ")))
        order = SUPPORT;
      /* test convoy next since convoy implies a move order */
      else if ((p1 = strstr (p0, " CONVOY")) || /* or CONVOYS */
        /* KDI - I included a copy of strrstr.c, and killed the NEXT
                special case */
         ((p1 = strrstr (p0, " C ")) && (strncmp (p0, "OFF BOARD", 9) > 0)))
        order = CONVOY;
      else if ((p1 = strstr (p0, " -> ")) ||
               (p1 = strstr (p0, " - ")) ||
               (p1 = strstr (p0, " M ")) ||
               (p1 = strstr (p0, " TO ")) ||
               (p1 = strstr (p0, " MOVE")))     /* or MOVES */
        order = MOVE;
      else if ((p1 = strstr (p0, " HOLD")) ||   /* or HOLDS */
               (p1 = strstr (p0, " H.")))
        order = HOLD;
      else if ((p1 = strstr (p0, ", NO ORDER PROCESSED")) ||
               (p1 = strstr (p0, ", NO MOVE RECEIVED")) ||
               (p1 = strstr (p0, " NMR")))
        order = NMR;

      if (order == UNKNOWN)
        {
          fprintf (stderr, "movement: unable to parse order:\n\t%s\n", line);
          break;
        }

      /* zap end of unit location */
      *(p1++) = '\0';

      /* third+ token(s) is the unit location */
      si = mapi (p0);
      if (si == 0)
        {
          fprintf (stderr, "movement: unable to parse unit location: %s\n", p0);
          break;
        }
      fprintf (nstdout, "\t%d %d %s\n",
               map[si].x, map[si].y, unit == 'A' ? "DrawArmy" : "DrawFleet");

      /* remember that we have a unit at this location */
      units[unitcount].country = (char *) strdup (country);
      string_check (units[unitcount].country, 1);
      units[unitcount].type = unit;
      units[unitcount].loc = si;/* unless it moves */

      if (strstr (msg, "DISLODGED") != NULL)
        {
          msg = "DISLODGED";    /* implies "cut" and/or "bounce" */
          --unitcount;          /* don't bother listing until it retreats */
        }

      /* ok, at this point, p1 points to the order */
      switch (order)
        {
        case CONVOY:
          /* try to point p0 at the initial, and p1 at the final destination */

          /* skip over order keyword */
          p0 = strchr (p1, ' ');
          if (string_check (p0, 0))
            break;
          ++p0;

          p2 = p0;

          /* skip over optional nationality */
          if (strncmp (p0, "ARMY ", 5) != 0 && strncmp (p0, "A ", 2) != 0)
            {
              p0 = strchr (p0, ' ');
              if (string_check (p0, 0))
                break;
              ++p0;
            }

          /* skip over unit type */
          if (strncmp (p0, "ARMY ", 5) != 0 && strncmp (p0, "A ", 2) != 0)
            {
              p0 = p2;          /* no unit type?, go back */
            }
          else
            {
              p0 = strchr (p0, ' ');
              if (string_check (p0, 0))
                break;
              ++p0;
            }

          /* ok, p0 points to a location, find the end of it and parse it */
          p1 = strstr (p0, " -");
          if (string_check (p1, 0))
            break;
          *(p1++) = '\0';
          di = mapi (p0);
          if (di == 0)
            {
              fprintf (stderr, "movement: unable to parse source location in convoy command: %s\n", p0);
              break;
            }

          /* find final destination */
          di2 = moveto (p1);
          if (di2 == 0)
            {
              fprintf (stderr, "movement: unable to parse destination location in convoy command: %s\n", p1);
              break;
            }
          sprintf (new, " %c %.3s C %.3s - %-6.6s %.9s",
                   unit, map[si].nick, map[di].nick, map[di2].nick, msg);
          if (fail)
            sprintf (newg, "FailedOrder %d %d %d %d %d %d ArrowConvoy OkOrder",
                     map[si].x, map[si].y,
                     map[di].x, map[di].y,
                     map[di2].x, map[di2].y);
          else
            sprintf (newg, "%d %d %d %d %d %d ArrowConvoy",
                     map[si].x, map[si].y,
                     map[di].x, map[di].y,
                     map[di2].x, map[di2].y);
          break;

        case HOLD:
          sprintf (new, " %c %.3s H              %.9s",
                   unit, map[si].nick, msg);
          break;

        case NMR:
          sprintf (new, " %c %.3s NMR            %.9s",
                   unit, map[si].nick, msg);
          break;

        case SUPPORT:
          /* support [[nationality type]|[type]] location [-> location]|[hold] */

          p0 = strchr (p1, ' ');/* skip over command */
          if (string_check (p0, 0))
            break;
          ++p0;

          p2 = (char *) strdup (p0);    /* save in case we don't have unit type */

          p1 = strchr (p0, ' ');/* tie off unit type */
          if (string_check (p1, 0))
            break;
          *(p1++) = '\0';       /* p1 points to source */
          if (!(strncmp (p0, "ARMY", strlen (p0)) == 0 ||
                strncmp (p0, "FLEET", strlen (p0)) == 0))
            {
              p0 = p1;          /* skip over nationality too */
              p1 = strchr (p0, ' ');    /* tie off unit type */
              if (p1)
                *(p1++) = '\0';
              if (p1 == NULL || (!(strncmp (p0, "ARMY", strlen (p0)) == 0 ||
                                   strncmp (p0, "FLEET", strlen (p0)) == 0)))
                {
                  p0 = NULL;    /* couldn't find unit type */
                  p1 = p2;      /* assume no nationality either */
                }
              else
                {
                  if (free (p2) == 0)
                    ;
                }
            }

          /* p1 points to source location */
          p0 = p1;              /* now p0 points to source too */

          if ((p1 = strstr (p0, " -")) == NULL)
            {                   /* supporting a unit holding */
              /* find end of location name */
              /* Special case Off Board H */
              p3 = p0;
              if (strstr (p0, "OFF BOARD H"))
                p3 += 11;
              if ((p1 = strstr (p3, " HOLD")) ||        /* or HOLDS */
                  (p1 = strstr (p3, " H.")) ||
                  (p1 = strstr (p3, " (*")) ||
                  (p1 = strchr (p3, '.')))
                *p1 = '\0';

              if (strlen (p0) == 2 && p1 != NULL)
                {
                  /* special case for St. Petersburg (sigh) */
                  *p1 = '.';    /* put back the period */
                  p1 = strchr (++p1, '.');
                  if (p1)
                    *p1 = '\0';
                }
              di = mapi (p0);
              if (di == 0)
                {
                  fprintf (stderr, "movement: unable to parse target of support command: %s\n", p0);
                  break;
                }
              sprintf (new, " %c %.3s S %.3s H        %.9s",
                       unit, map[si].nick, map[di].nick, msg);
              if (fail)
                sprintf (newg, "FailedOrder %d %d %d %d ArrowHold OkOrder",
                         map[si].x, map[si].y,
                         map[di].x, map[di].y);
              else
                sprintf (newg, "%d %d %d %d ArrowHold",
                         map[si].x, map[si].y,
                         map[di].x, map[di].y);
            }
          else
            {                   /* support a unit moving */
              *(p1++) = '\0';
              di = mapi (p0);
              if (di == 0)
                {
                  fprintf (stderr, "movement: unable to parse first target of support command: %s\n", p0);
                  break;
                }
              di2 = moveto (p1);
              if (di2 == 0)
                {
                  fprintf (stderr, "movement: unable to parse second target of support command: %s\n", p1);
                  break;
                }
              sprintf (new, " %c %.3s S %.3s - %-6.6s %.9s",
                       unit, map[si].nick, map[di].nick, map[di2].nick, msg);
              if (fail)
                sprintf (newg, "FailedOrder %d %d %d %d %d %d ArrowSupport OkOrder",
                         map[si].x, map[si].y,
                         map[di].x, map[di].y,
                         map[di2].x, map[di2].y);
              else
                sprintf (newg, "%d %d %d %d %d %d ArrowSupport",
                         map[si].x, map[si].y,
                         map[di].x, map[di].y,
                         map[di2].x, map[di2].y);
            }
          break;

        case MOVE:
          di = moveto (p1);
          if (di == 0)
            {
              fprintf (stderr, "movement: unable to parse destination of move command: %s\n", p1);
              break;
            }
          sprintf (new, " %c %.3s - %-6.6s       %.9s",
                   unit, map[si].nick, map[di].nick, msg);

          if (fail)
            sprintf (newg, "FailedOrder %d %d %d %d ArrowMove OkOrder",
                     map[si].x, map[si].y,
                     map[di].x, map[di].y);
          else
            {
              units[unitcount].loc = di;
              sprintf (newg, "%d %d %d %d ArrowMove",
                       map[si].x, map[si].y,
                       map[di].x, map[di].y);
            }
          break;
        }

      ++unitcount;

      /* if we didn't parse an order, exit the while loop now */
      if (new[0] == '\0')
        break;

      /* transfer current order to save array */
      if (new[0] != '\0')
        {
          orders[ordernum] = (char *) strdup (new);
          string_check (orders[ordernum], 1);
          ++ordernum;
        }
      if (newg[0] != '\0')
        {
          graphics[graphicnum] = (char *) strdup (newg);
          string_check (graphics[graphicnum], 1);
          ++graphicnum;
        }

      if (ordernum == MAXORDERS)
        {                       /* error check... */
          fprintf (stderr, "movement: too many orders, some will be lost (sorry)\n");
          --ordernum;           /* drop the last one */
        }

      error = 0;                /* no error occured! */
    }

  if (error)
    fprintf (stderr, "movement: error occured on line:\n\t%s\n", line);

  if (ordernum > 0)
    {
      fprintf (nstdout, "OrderReport\n");
      for (i = 0; i < ordernum; i++)
        {
          fprintf (nstdout, "(%s) WriteOrder\n", orders[i]);
          if (free (orders[i]) == 0)
            ;
        }
    }

  if (graphicnum > 0)
    {
      for (i = 0; i < graphicnum; i++)
        {
          fprintf (nstdout, "%s\n", graphics[i]);
          if (free (graphics[i]) == 0)
            ;
        }
    }
}

/*
  ADJUSTMENT ORDERS

  [country:] [build | remove | pending | waived | defaults].

  build         BUILDS [[A fleet | AN army] IN [THE] | unit] location
  remove        REMOVES [THE unit IN [THE] | unit] location
  pending       n [UNUSABLE] BUILD[S] PENDING
  waived        BUILD WAIVED
  defaults      DEFAULTS, REMOVING [THE unit IN [THE] | unit] location
  ADJUSTMENT ORDERS

  [country:] [build | remove | pending | waived | defaults].

  build         BUILDS [[A fleet | AN army] IN [THE] | unit] location
  remove        REMOVES [THE unit IN [THE] | unit] location
  pending       n [UNUSABLE] BUILD[S] PENDING
  waived        BUILD WAIVED
  defaults      DEFAULTS, REMOVING [THE unit IN [THE] | unit] location
*/
parse_adjustment ()
{
  char line[BUFSIZ], copy[BUFSIZ];
  char report[BUFSIZ];          /* line being built to output */
  char t1[BUFSIZ], t2[BUFSIZ];  /* two tokens parsed from line */
  char *p0, *p1;                /* misc pointers */
  char country[BUFSIZ];         /* current country being processed */
  char unit;                    /* type of unit A or F */
  int count;                    /* count of units for this country */
  int ci;                       /* index of center */
  int pending;                  /* true if line is a special message */
  int i, j, k;                  /* misc counters */
  int building;                 /* true if building units */
  int error;                    /* true if an error occurs during parse */

  fprintf (nstdout, "AdjustReport\n");
  strcpy (country, "unknown");
  count = 0;
  report[0] = '\0';
  gets (line);                  /* skip blank line */
  error = 0;
  while (gets (line))
    {

      if (line[0] == '\0' || line[0] == ' ' || line[0] == '\t')
        continue;               /* skip blank and comment lines */

      copyline (copy, line);

      if (strncmp (copy, "THE ", 4) == 0 ||
          strncmp (copy, "END", 3) == 0)
        break;                  /* end of adjustment results */

      if (strncmp (copy, "OWNERSHIP", 9) == 0)
        {
          /* end of adjustment results, and start of fall report */
          parse_fall_report ();
          break;
        }
      error = 1;                /* if we break out now, it is an error */

      /* these keywords indicate a build which did not happen */
      if (strstr (copy, "PENDING") || strstr (copy, "WAIVED"))
        pending = 1;
      else
        pending = 0;

      p1 = strpbrk (copy, ": ");
      if (p1 == NULL || *p1 == ':')
        {                       /* yes, this is a country tag */
          if (p1 != NULL)
            *(p1++) = '\0';     /* zap the colon */
          p0 = copy;
          if (strcmp (p0, country) != 0)
            {
              /* start new country */
              strcpy (country, p0);
              if (report[0] != '\0')
                fprintf (nstdout, "(%s) WriteAdjust\n", report);
              sprintf (report, "%-10s", country);
              count = 0;
            }
          if (p1 == NULL || *p1 == '\0')
            continue;           /* just a country token, get next line */
        }
      else
        p1 = copy;              /* nope, not a country tag, reset to start */

      if (*p1 == ' ')
        ++p1;

      if (pending)
        {
          if (count++)
            /* if (strlen(report) && report[strlen(report) - 1] == '.')
                  report[strlen(report) - 1] = 0;
                */
            strcat (report, ", ");
          strcat (report, p1);
          error = 0;
        }
      else
        {
          /* try to parse the rest of the line */
          if (strncmp (p1, "DEFAULTS, ", 10) == 0)
            {
              if (count == 0)
                strcat (report, "*REMOVES ");
              p1 += 10;
              building = 0;
            }
          else if (strncmp (p1, "BUILD", 5) == 0)
            {
              if (count == 0)
                strcat (report, "BUILDS ");
              building = 1;
            }
          else
            {
              if (count == 0)
                strcat (report, "REMOVES ");
              building = 0;     /* anything else is a disband */
            }

          j = sscanf (p1, "%*s %*s %s IN THE %[A-Z.-() ]", t1, t2);
          if (j != 2)           /* try without the word THE */
            j = sscanf (p1, "%*s %*s %s IN %[A-Z.-() ]", t1, t2);
          if (j != 2)           /* try without A/AN and IN */
            j = sscanf (p1, "%*s %s %[-A-Z0-9.() /]", t1, t2);
          if (j != 2)
            {
              fprintf (stderr, "adjustment: unable to parse adjustment order\n");
              break;
            }
          if (count++)
            strcat (report, ", ");
          unit = t1[0];
          if (unit == 'A')
            strcat (report, "A ");
          else if (unit == 'F')
            strcat (report, "F ");
          else
            {
              fprintf (stderr, "adjustment: unable to parse adjustment order, expecting ARMY or FLEET keyword\n");
              break;
            }
          i = strlen (t2);      /* strip off trailing period */
          if (t2[i - 1] == '.')
            t2[i - 1] = '\0';
          ci = mapi (t2);
          if (ci == 0)
            {
              fprintf (stderr, "adjustment: unable to parse site of build/disband command: %s\n", t2);
              break;
            }
          strcat (report, map[ci].nick);

          error = 0;            /* made it this far, line is good */

          if (building)
            {
              /* add to new map */
              units[unitcount].country = (char *) strdup (country);
              units[unitcount].type = unit;
              units[unitcount].loc = ci;
              ++unitcount;
            }
          else
            {
              /* remove (first unit found) from map */
              for (i = 0; i < unitcount; ++i)
                {
                  if (strncmp (map[units[i].loc].nick, map[ci].nick, 3) == 0)
                    {
                      units[i].loc = 0;
                      break;
                    }
                }
            }
        }
    }

  if (error)
    fprintf (stderr, "adjustment: error occured on line:\n\t%s\n", line);

  if (report[0] != '\0')
    fprintf (nstdout, "(%s) WriteAdjust\n", report);

}

/*
  RETREAT ORDERS

  [country:] move_order | disband | nop.

  disband       unit location DISBAND
  nop           unit location, NO ORDER PROCESSED (DISBAND)
*/
parse_retreat ()
{
  char line[BUFSIZ], copy[BUFSIZ];
  char *p0, *p1, *p2, *msg;
  int fail;
  char country[BUFSIZ];         /* nation */
  int si, di;                   /* source and destination */
  char unit;                    /* unit type */
  int i, j, k;
  int error;

  country[0] = '\0';
  fprintf (nstdout, "RetreatReport\n");
  error = 0;                    /* no error, ok to exit loop */
  while (gets (line))
    {
      if (line[0] == '\0' || line[0] == ' ' || line[0] == '\t')
        continue;               /* skip blank and comment lines */

      copyline (copy, line);

/* MORE MJH */
	  if (strstr (copy, "INCOME HAS BEEN DISTRIBUTED") != NULL)
	  	continue;
/* END MORE MJH */

      if (strncmp (copy, "THE ", 4) == 0 ||
          strncmp (copy, "END", 3) == 0)
        break;                  /* end of adjustment results */

      if (strncmp (copy, "OWNERSHIP", 9) == 0)
        {
          /* end of retreat results, and start of fall report */
          parse_fall_report ();
          break;
        }
      error = 1;                /* signal error if we break out now */

      p1 = strpbrk (copy, ": ");
      if (p1 == NULL || *p1 == ':')
        {                       /* yes, this is a country tag */
          if (p1 != NULL)
            *(p1++) = '\0';     /* zap the colon */
          p0 = copy;
          if (strcmp (p0, country) != 0)
            strcpy (country, p0);
          if (p1 == NULL || *p1 == '\0')
            continue;           /* just a country token, get next line */
        }
      else
        p1 = copy;              /* nope, not a country tag, reset to start */

      /* second token is the unit type... */
      if (*p1 == ' ')
        ++p1;
      unit = *p1;
      p0 = strchr (p1, ' ');
      if (p0 == NULL)
        {
          fprintf (stderr, "retreat: expected [country] unit location order\n");
          break;
        }
      else
        *(p0++) = '\0';         /* tie it off */
      if (!(strncmp (p1, "ARMY", strlen (p1)) == 0 ||
            strncmp (p1, "FLEET", strlen (p1)) == 0))
        {
          fprintf (stderr, "retreat: expected unit (ARMY or FLEET), got %s\n", p1);
          break;
        }

      if (p1 = strstr (p0, "DISBAND"))
        {
          /* zap end of unit location */
          *(p1 - 1) = '\0';

          /* DCK */
          if (p1 = strstr (p0, ", NO ORDER"))
            {
              /* zap again */
              *(p1) = '\0';
            }

          /* third+ token(s) is the unit location */
          si = mapi (p0);
          if (si == 0)
            {
              fprintf (stderr, "retreat: unable to parse site of disband command: %s\n", p0);
              break;
            }

          fprintf (nstdout, "(%-10s %c %.3s DISBANDS) WriteRetreat\n",
                   country, unit, map[si].nick);

          /* remove (first unit found) from map */

/* Don't remove unit - dislodged units are never entered into units[i]. - MP */

/*    for(i=0; i<unitcount; ++i) {
        if (units[i].loc == si) {
          units[i].loc = 0;
          break;
        }
      }

   end of code removal */

        }
      else
        {                       /* not a disband, must be a real retreat */
          p1 = strstr (p0, " -");

          /* zap end of unit location */
          if (p1)
            {
              *(p1++) = '\0';
              /* third+ token(s) is the unit location */
              si = mapi (p0);
            }
          else
            si = 0;
          if (si == 0)
            {
              fprintf (stderr, "retreat: unable to parse site of retreat command: %s\n", p0);
              break;
            }

          p0 = strrchr (p1, '>') + 2;   /* skip to final dest */

          /* first remove any message from the end of the line */
          /* anything between two stars is the message */
          msg = "";
          fail = 0;
          if ((p2 = strstr (p0, " (*")) != NULL)
            {                   /* Found the start of a message */
              p1 = strstr (p2, "*)");
              if (p1 != NULL)
                *p1 = '\0';
              else
                {               /* Did not find the end of the message */
                  fprintf (stderr, "retreat: expected command (*message*)\n");
                  break;
                }
              *p2 = '\0';
              msg = p2 + 3;
              fail = 1;
            }

          if (fail)
            {
              if (strstr (msg, "BOUNCE") != NULL)
                msg = "BOUNCE";
              else
                msg = "FAILED";
            }

          p1 = strchr (p0, '.');/* command ends at a period */
          if (p1 == NULL)
            p1 = strstr (p0, " (*");    /* or before a message */
          if (p1 != NULL)
            *p1 = '\0';         /* or at the end of the line */

          if (strlen (p0) == 2 && p1 != NULL)
            {
              /* special case for St. Petersburg (sigh) */
              *p1 = '.';        /* put back the period */
              p1 = strchr (++p1, '.');
              *p1 = '\0';
            }
          di = mapi (p0);
          if (di == 0)
            {
              fprintf (stderr, "retreat: unable to parse destination of retreat command: %s\n", p0);
              continue;
            }

          fprintf (nstdout, "(%-10s %c %.3s - %-6.6s %.9s) WriteRetreat\n",
                   country, unit, map[si].nick, map[di].nick, msg);

          if (!fail)
            {
              units[unitcount].country = (char *) strdup (country);
              units[unitcount].type = unit;
              units[unitcount].loc = di;
              ++unitcount;
            }
        }
      error = 0;
    }
  if (error)
    fprintf (stderr, "retreat: error occured on line:\n\t%s\n", line);

}

/*
  The keyword OWNERSHIP begins a game status summary section begins a
  game status summary section which consists of two parts, a support
  center ownership followed by an adjustment summary.

  SUPPORT CENTER OWNERSHIP

  country: location [, location].

  In this section, there may be continuation lines which begin with
  whitespace. A country line ends with a period.

  ADJUSTMENT SUMMARY

  country: n SUPPLY CENTERS, n UNITS: [BUILDS | REMOVES] n UNIT[S].

  Note: a unit location should not contain a period. But an exception
  is allowed for something like "St. Petersburg". A coast location is
  written "FOO/xx". If a (destination) location contains a dash then a
  single dash can not be used to indicate a move, use -> instead.
*/
parse_fall_report ()
{
  char line[BUFSIZ], copy[BUFSIZ], temp[BUFSIZ];
  char report[BUFSIZ];
  char *p0, *p1, *colon;
  char country[BUFSIZ], save[BUFSIZ];
  int centers, units;
  int ci;                       /* index of center in map database */
  int i, j, k;

/* ADDED BY MJH */
  buffer[0] = 0;

  /* first we have ownership report */
  fprintf (nstdout, "OwnerReport\n");
  gets (line);                  /* skip blank line */
  strcpy (country, "unknown");
  report[0] = '\0';
  save[0] = '\0';
  while (gets (line) && strlen (line) > 0)
    {
      if (save[0])
        {                       /* this should be a continuation line */
          if (line[0] != ' ')
            {
              fprintf (stderr, "ownership: expecting continuation line\n\t%s\n", line);
              break;
            }
          sprintf (temp, "%s %s", save, line);
          copyline (copy, temp);
        }
      else
        copyline (copy, line);

      save[0] = '\0';

      p1 = strpbrk (copy, ": ");
      if (p1 == NULL || *p1 == ':')
        {                       /* yes, this is a country tag */
          if (p1 != NULL)
            *(p1++) = '\0';     /* zap the colon */
          p0 = copy;
          if (strcmp (p0, country) != 0)
            {
              /* start new country */
              strcpy (country, p0);
              if (report[0] != '\0')
                fprintf (nstdout, "(%s) WriteOwner\n", report);
              sprintf (report, "%-10s ", country);
/* ADDED BY MJH */
              sprintf (buffer + strlen (buffer), "%sCENTER\n", country);
            }
          if (p1 == NULL || *p1 == '\0')
            continue;           /* just a country token, get next line */
        }
      else
        p1 = copy;              /* nope, not a country tag, reset to start */

      if (new_borders)
        ownernum = ownerlookup (country);


      p0 = p1 + strlen (p1);
      *p0 = ' ';                /* mark end of line with a trailing blank */
      *(++p0) = '\0';


      /* now translate every center name on the line, printing as we go */
      for (p1 = strtok (p1, ",."); p1 != NULL; p1 = strtok (NULL, ",."))
        {
          if (*p1 == ' ')
            ++p1;               /* skip leading white space */

          if (*p1 == '\0')
            break;              /* found eol token */

          if (strlen (p1) == 2)
            {                   /* damn St. Petersburg again */
              p0 = p1;          /* save pointer */
              p1 += 2;          /* advance to end */
              *(p1++) = '.';    /* put back the period */
              p1 = strtok (p1, ".,");   /* look for next period/comma */
              p1 = p0;          /* reset pointer to start of name */
            }

          /* are we at the eol? */
          if (p1[strlen (p1) - 1] == ' ')
            {
              strcpy (save, p1);/* yes, save last token for use with next line */
              break;
            }

          if ((ci = mapi (p1)) > 0)
            {
              strcat (report, " ");
              strcat (report, map[ci].nick);
              if (new_borders
                  /*       && (ownerlist[countrynum(map[ci].nick)] == -1)) */ )
                ownerlist[countrynum (map[ci].nick)] = ownernum;
/* ADDED BY MJH */
              sprintf (buffer + strlen (buffer), "%s supply\n", map[ci].nick);
            }
          else
            {
              fprintf (stderr, "ownership: unable to parse location: %s\n", p1);
              break;
            }
        }
    }
  if (report[0] != '\0')
    fprintf (nstdout, "(%s) WriteOwner\n", report);

  /* then we have status report */
  fprintf (nstdout, "StatusReport\n");
  while (gets (line) && strlen (line) > 0)
    {
      copyline (copy, line);
      if ((colon = strchr (copy, ':')))
        *colon = ' ';
      i = sscanf (copy, "%s %d %*s %*s %d", country, &centers, &units);
      if (i == 3)
        {
          fprintf (nstdout, "(%-7s: %2d/%-2d) WriteStatus\n", country, units, centers);
        }
      else
        fprintf (stderr, "ownership: unable to parse status line:\n\t%s\n", line);
    }
}

/*
  STARTING POSITION

  [country:] unit location.

If it is a Status Report, it might include retreat options

  [country:] unit location [can retreat to location [or location]]

*/
parse_start (report)
     int report;
{
  char line[BUFSIZ];            /* the current order being processed */
  char copy[BUFSIZ];            /* a temp copy */
  char *p0, *p1, *p2;           /* some char pointers */
  int i, j, k;                  /* misc counters */

  char country[BUFSIZ];
  char unit;                    /* unit type, "A" or "F" */
  int order;                    /* one of the following: */
  int si;                       /* index of source location) */

#define MAXORDERS MAXUNITS
  char *orders[MAXORDERS];      /* orders to write to the left of the map */
  char new[BUFSIZ];             /* current order being formed */
  int ordernum;                 /* count of orders */

  int x, y;                     /* map coordinate of support/convoy arrow */
  int error;                    /* true if a syntax (or malloc) error */

  for (i = 0; i < unitcount; ++i)
    {
      if (free (units[i].country) == 0)
        ;
    }
  unitcount = 0;

  strcpy (country, "unknown");
  ordernum = 0;
  error = 0;
  while (gets (line))
    {
      new[0] = '\0';

      if (line[0] == '\0' || line[0] == ' ' || line[0] == '\t')
        continue;

      copyline (copy, line);    /* first make a copy of it */

      /* see if we are at the end of this section... */
      if (strncmp (copy, "THE ", 4) == 0 ||
          strncmp (copy, "END", 3) == 0)
        break;                  /* end of adjustment results */
      if (strncmp (copy, "OWNERSHIP", 9) == 0)
        {
          /* end of adjustment results, and start of fall report */
          parse_fall_report ();
          break;
        }

      /* still here, parse the line... */

      /* is the first/only token a country specifier? */
      p1 = strpbrk (copy, ":");
      if (p1 == NULL || *p1 == ':')
        {                       /* yes, this is a country tag */
          if (p1 != NULL)
            *(p1++) = '\0';     /* zap the colon */
          p0 = copy;
          if (strcmp (p0, country))
            {
              strcpy (country, p0);     /* start new country */
              fprintf (nstdout, "%s\n", country);
              orders[ordernum] = (char *) strdup (country);
              string_check (orders[ordernum], 1);
              ++ordernum;
            }                   /* otherwise just continue on */
        }
      else
        p1 = copy;              /* no, token is not a country tag */

      if (p1 == NULL || *p1 == '\0')
        continue;               /* nothing else on this line */

      error = 1;                /* no errors past this point */

      /* p0 maybe points to country, p1 points to next token */

      /* next token is the unit type... */
      if (*p1 == ' ')
        ++p1;
      unit = *p1;

      /* find next token, a location name */
      p0 = (strchr (p1, ' '));
      if (string_check (p0, 0))
        {
          fprintf (stderr, "start: expected [country:] unit location.\n");
          break;
        }
      else
        *(p0++) = '\0';
      if (!(strncmp (p1, "ARMY", strlen (p1)) == 0 ||
            strncmp (p1, "FLEET", strlen (p1)) == 0))
        {
          fprintf (stderr, "start: expected unit (ARMY or FLEET), got %s\n", p1);
          break;
        }

      if (report == SR)
        {
          /* retreat report might list possible retreat options on the line */
#define CANRETREAT " CAN RETREAT TO "
          p1 = strstr (p0, CANRETREAT);
          if (p1)
            {
              *(p1) = '.';
              p2 = p1 + strlen (CANRETREAT);
            }
          else
            p2 = NULL;
        }
      else
        p2 = NULL;

      p1 = strchr (p0, '.');
      if (p1)                   /* let period be optional */
        *p1 = '\0';             /* zap end of unit location */
      if (strlen (p0) == 2 && p1)
        {                       /* looks like St. Petersburg */
          *p1 = '.';            /* put period back */
          p1 = strchr (++p1, '.');      /* and try again */
          if (p1)
            *p1 = '\0';
        }

      /* third+ token(s) is the unit location */
      si = mapi (p0);
      if (si == 0)
        {
          fprintf (stderr, "start: unable to parse unit location: %s\n", p0);
          break;
        }
      fprintf (nstdout, "\t%d %d %s\n",
               map[si].x, map[si].y, unit == 'A' ? "DrawArmy" : "DrawFleet");

/*    if(new_borders)
      ownerlist[si] = ownerlookup(country); */

      /* XXX todo: parse mulitiple retreat sites and print nicknames */
      if (p2 != NULL)           /* p2 points to retreat comment */
        if (strchr (p2, ',') != NULL)   /* more than one choice */
          sprintf (new, " %c %s (-> ???)", unit, map[si].nick);
        else
          sprintf (new, " %c %s (-> %s)", unit, map[si].nick, p2);
      else
        {
          sprintf (new, " %c %s", unit, map[si].nick);

          /* remember that we have a unit at this location */
          units[unitcount].country = (char *) strdup (country);
          string_check (units[unitcount].country, 1);
          units[unitcount].type = unit;
          units[unitcount].loc = si;
          ++unitcount;
        }

      /* transfer current order to save array */
      orders[ordernum] = (char *) strdup (new);
      string_check (orders[ordernum], 1);
      ++ordernum;

      if (ordernum == MAXORDERS)
        {                       /* error check... */
          fprintf (stderr, "start: too many orders, some will be lost (sorry)\n");
          --ordernum;           /* drop the last one */
        }

      error = 0;
    }

  if (error)
    fprintf (stderr, "start: error occured on line:\n\t%s\n", line);

  if (ordernum > 0)
    {
      fprintf (nstdout, "OrderReport\n");
      for (i = 0; i < ordernum; i++)
        {
          fprintf (nstdout, "(%s) WriteOrder\n", orders[i]);
          if (free (orders[i]) == 0)
            ;
        }
    }
}

/* given a string with a move order, find the (final) destination */
moveto (s)
     char *s;
{
  char copy[BUFSIZ];
  char *p0, *p1;

  strcpy (copy, s);
  p0 = copy;

  p1 = strrchr (p0, '>');       /* skip over all -> to final dest */
  if (p1 == NULL)               /* no ->, must be - */
    p1 = strrchr (p0, '-');     /* XXX mid-atlantic will break this */
  if (p1 && strlen (p1) > 2)
    p1 += 2;
  else
    return 0;

  /* now p1 points to start of location name, find the end */
  p0 = strchr (p1, '.');        /* command ends at a period */
  if (p0 == NULL)
    p0 = strstr (p1, " (*");    /* or before a message */
  if (p0 != NULL)
    *p0 = '\0';                 /* tie off the name */

  if (p0 != NULL && strlen (p1) == 2)
    {
      /* special case for St. Petersburg (sigh) */
      *p0 = '.';                /* put back the period */
      p0 = strchr (++p0, '.');  /* look for the real ending period */
      if (p0 == NULL)
        p0 = strstr (p1, " (*");/* or before a message */
      if (p0 != NULL)
        *p0 = '\0';             /* tie off the name */
    }

  return (mapi (p1));
}

country_compare (u1, u2)
     struct unitstruct *u1, *u2;
{
  return strcmp (u1->country, u2->country);
}

drawmap (title, message)
     char *title, *message;
{
  int i;

  fprintf (nstdout, "DrawMap\n");
  if (title != NULL && *title != '\0')
    fprintf (nstdout, "(%s) DrawTitle\n", title);
  if (message != NULL && *message != '\0')
    fprintf (nstdout, "(%s) DrawMessage\n", message);
  for (i = 1; i <= mapcount; ++i)       /* label provinces */
    if (map[i].nick[3] != '/')  /* don't label coasts */
      fprintf (nstdout, "%d %d (%s) DrawName\n", map[i].x, map[i].y, map[i].nick);
}

/* given the new unit positions, draw a new map */
drawnew ()
{
  int i, j, k;
  char country[BUFSIZ];

  if (unitcount == 0)
    return;

  qsort (units, unitcount, sizeof (struct unitstruct), country_compare);

  /* run though twice, once to draw units, and once to draw order list */
  strcpy (country, "unknown");
  for (i = 0; i < unitcount; ++i)
    {
      if (strcmp (country, units[i].country))
        {
          strcpy (country, units[i].country);
          fprintf (nstdout, "%s\n", country);
        }
/* Update borders from finishing positions - units position takes priority
   over ownership of centre */
      if (units[i].loc > 0)
        ownerlist[units[i].loc] = ownerlookup (country);
      if (units[i].loc > 0)
        fprintf (nstdout, "\t%d %d %s\n",
                 map[units[i].loc].x, map[units[i].loc].y,
                 units[i].type == 'A' ? "DrawArmy" : "DrawFleet");
    }

  fprintf (nstdout, "OrderReport\n");
  strcpy (country, "unknown");
  for (i = 0; i < unitcount; ++i)
    {
      if (strcmp (country, units[i].country))
        {
          strcpy (country, units[i].country);
          fprintf (nstdout, "(%s) WriteOrder\n", country);
        }
      if (units[i].loc > 0)
        fprintf (nstdout, "( %c %s) WriteOrder\n",
                 units[i].type, map[units[i].loc].nick);
      if (free (units[i].country) == 0)
        ;
    }
  unitcount = 0;
}

/* copy s2 to s1, uppercase, squeeze whitespace */
copyline (s1, s2)
     char *s1, *s2;
{
  int white;                    /* white space seen */

  white = 0;
  for (*s1 = *s2; *s2 != '\0'; ++s2)
    {
      if (*s2 == ' ' || *s2 == '\t')
        {
          if (!white)
            {
              *(s1++) = ' ';
              ++white;
            }
        }
      else
        {
          white = 0;
          if (islower (*s2))
            *(s1++) = toupper (*s2);
          else
            *(s1++) = *s2;
        }
    }
  *s1 = '\0';
  if (*(--s1) == ' ')           /* strip trailing blank */
    *s1 = '\0';

}

string_check (s, fatal)
     char *s;
     int fatal;
{
  if (s == NULL)
    {
      fprintf (stderr, "?: unexpected error, null string pointer\n");
      if (fatal)
        {
          fprintf (stderr, "?: can not continue\n");
          exit (1);
        }
      else
        {
          fprintf (stderr, "?: aborting this section\n");
          return 1;
        }
    }
  else
    return 0;
}

/* init reads the 2 files described above... */
init ()
{
  char *fn;
  FILE *f;
  char line[BUFSIZ], copy[BUFSIZ], nick[BUFSIZ], owner[BUFSIZ], name[BUFSIZ],
    nicks[BUFSIZ];
  int x, y;
  int i, j, k;

  unitcount = 0;
  nationcount = 0;

  map[0].name = "Unknown";
  map[0].nick = "???";
  map[0].owner = "???";         /* For the -b option */
  map[0].nicks = "";
  map[0].x = 0;
  map[0].y = 0;
  /* map[0].in_ps = 0; mark province not in postscript map TKU */
  mapcount = 0;


  if (info_file != NULL)
    fn = info_file;
  else
    fn = (char *) getenv ("MAPINFO");
  if (fn == NULL)
    fn = DEFAULT_INFO;
  if (f = fopen (fn, "r"))
    {
      j = 0;
      while (fgets (line, BUFSIZ, f))
        {                       /* first section is just a list of nations */
          if (line[0] == '#' || line[0] == ' ')
            continue;           /* skip comment lines */
          if (line[0] == '-')
            break;              /* end of section */
          copyline (copy, line);
     for(i=0;copy[i];i++) if (copy[i]=='\n') break;
     copy[i] = '\0';  /* terminate nationname with '\0' instead of '\n' TKU*/
          nation[nationcount] = (char *) strdup (copy);
     nation_in_ps[nationcount] = 0; /* powername not in postscript map TKU */
          string_check (nation[nationcount], 1);
          if (++nationcount == MAXNATIONS)
            {
              fprintf (stderr, "init: sorry, program only supports %d nations\n", MAXNATIONS);
              exit (1);
            }
        }

      while (fgets (line, BUFSIZ, f))
        {                       /* next section is location definitions */
          if (line[0] == '#' || line[0] == ' ')
            continue;           /* skip comment lines */
          if (line[0] == '-')
            break;              /* end of section */
          copyline (copy, line);
          i = sscanf (copy, "%d %d |%[^|]|%[^|]|%[^|]%[-|0-9A-Z.() ]",
                      &x, &y, nick, owner, name, nicks);
          if (i < 4)
            fprintf (stderr, "init: expected xpos ypos |nick|full name|[nick2|...|]\n\t%s\n", line);
          else
            {
              if (++mapcount == MAXNAMES)
                {
                  fprintf (stderr, "init: sorry, program only supports %d map locations\n", MAXNAMES);
                  exit (1);
                }
              map[mapcount].x = x;
              map[mapcount].y = y;
              map[mapcount].nick = (char *) strdup (nick);
              map[mapcount].name = (char *) strdup (name);
              map[mapcount].owner = (char *) strdup (owner);
              /* map[mapcount].in_ps = 0; province not in ps-map TKU */
              if (i < 5)
                nicks[0] = '\0';;
              map[mapcount].nicks = (char *) strdup (nicks);
              if (nick[3] == '/')
                ++j;
            }
        }
      fclose (f);
      fprintf (stderr, "init: read %d location definitions (%d regular, %d coasts)\n", mapcount, mapcount - j, j);
    }
  else
    {
      fprintf (stderr, "init: unable to read MAPINFO file (%s)\n", fn);
      return 1;
    }

  /* we don't do anything with the PS file other than copy it to stdout */
  /* PS-map file is read after processing info-file, so we can check if
     special PostScript commands for Powers and Provinces are in it,
     used for coloured supply centers.
     NOTE the .cmap.ps has to include s.t. like:
     /${POWERNAME}CENTER { ...color...} def
     /${PROVINCENICK} { xpos ypos } def
     for each power and each province. The pattern machting below
     searches only for the occurence of the uppercase powernames
     beginning in the 2nd column of a line. TKU */
  if (ps_file != NULL)
    fn = ps_file;
  else
    fn = (char *) getenv ("MAPPS");
  if (fn == NULL)
    fn = DEFAULT_PS;
  if (f = fopen (fn, "r")) {
      while (fgets (line, BUFSIZ, f)) {
                fprintf (nstdout, "%s", line);
           if (colored_supplies != AUTODETECT) continue;
                          if (*line!='/') continue;
           /* check if power(nation)-name is defined in PostScript-map TKU */
                for(i=nationcount;i--;) if ( (!nation_in_ps[i])
               && (!strncmp(nation[i],line+1,j=strlen(nation[i])))
               && (!strncmp("CENTER",line+1+j,6)) )
               { nation_in_ps[i] = !0; break; }
  /* DONT check if province(map)-name because we only need to check
     supply centers
                for(i=mapcount;i--;) if ( (!map[i].in_ps)
               && (!strncmp(map[i].nick,line+1,strlen(map[i].nick))) )
               { map[i].in_ps = !0; break; }
   */
      }
      fclose (f);
  } else {
      fprintf (stderr, "init: unable to read MAPPS file (%s)\n", fn);
      return 1;
  }
  if (colored_supplies == UNCOLORED_SC) return 0;
  /* check if ALL power-names have been defined in PostScript map TKU */
  colored_supplies = UNCOLORED_SC;  /* this is the default */
  for(i=nationcount;i--;) if (!nation_in_ps[i]) return 0; /* uncolored SCs */
  /* check if ALL province(map)-names have been defined in PostScript-map TKU
  for(i=mapcount;i--;) if (!map[i].in_ps) return 0;
  */
  colored_supplies = COLORED_SC;/* every power and province definied in map */
  fprintf(stderr,"init: found color map with coloured supply centers: %s\n",fn);
  return 0;
}

mapi (name)                     /* return index of map table entry */
     char *name;
{
  int i, j, k;
  char t[BUFSIZ];

  sprintf (t, "|%s|", name);
  for (i = 1; i < MAXNAMES; ++i)
    {
      if (map[i].name == NULL)
        break;
      if (strcmp (map[i].name, name) == 0 ||    /* full name */
          strcmp (map[i].nick, name) == 0 ||    /* official nick name */
          strstr (map[i].nicks, t) != NULL)     /* other nicknames */
        return i;
/* ADDED BY MJH FOR SAIL_HO */
	  if (strncmp(map[i].name, name, strlen(name)) == 0) return i;
    }
  return 0;
}

int PagesSoFar = 0;
/* StartPage
   Outputs the appropriate postscript comments to start a page to start
 */
StartPage ()
{
  PagesSoFar++;
  fprintf (nstdout, "%%%%Page: %d %d\n", PagesSoFar, PagesSoFar);
  fprintf (nstdout, "%%%%PageBoundingBox: 0 0 792 612\n");      /* 11 x 8.5 */
}

/* EndPage
   Outputs the appropriate postscript comments to end a page to start
 */
EndPage ()
{
  fprintf (nstdout, "%%%%PageTrailer\n");
}

/* EndDocument
   Outputs the appropriate postscript comments to end the whole thing
 */
EndDocument ()
{
  fprintf (nstdout, "%%%%Trailer\n");
  fprintf (nstdout, "%%%%Pages: %d 1\n", PagesSoFar);
  fprintf (nstdout, "%%%%BoundingBox:0 0 612 792\n");
}


/* Some procedures for the -b option */

int 
same_owner (c1, c2)
     char *c1, *c2;
{
  return (ownerlist[countrynum (c1)] == ownerlist[countrynum (c2)]);
}

int 
countrynum (country)
     char *country;
{
  int i;

  for (i = 0; i < MAXNAMES; ++i)
    if (!strncmp (map[i].nick, country, 3))
      return i;
  fprintf (stderr, "Error in countrynum.\n");
  return 0;
}

int 
ownerlookup (country)
     char *country;
{
  int i;

  for (i = 0; i < nationcount; ++i)
    if (nation[i][0] == country[0])
      return i;
  return -1;
}

