/*
  Routine to read the 'traj_ice.dat' file and extract specific fields.  The
  user supplies the list of field numbers to be retrieved in the command line.
  The fields are extracted in the order specified and output to 'stdout'
  without reformatting.  Field ranges may be specified provided no space is 
  left between the hyphen and the field numbers.  The "-h" option specifies
  that the field headers (from record 1) should also be extracted and sent to
  the output file.

  Note that there are no record delimiters in the data file.

  Format:

     % extraj [-h] [field1] ... [field_n-field_m] ...

  Note that inthe input list the first field is field 1, as in the documentation
  file, but in the program that same field is referred to as field 0.  The table
  created has both carriage return AND line feed characters (\r\n).

  07 December 1995, acr.

*/

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <errno.h>

#define  EPHEMERIS_FILE  "traj_ice.dat"
#define  RECORD_LENGTH   2736
#define  MAX_FIELDS      200

/* 
  The ephemeris record consists of 114 24-bytes fields, so the position of
  any single fields is easily calculated from the field number.  The 24 bytes
  includes blank delimiters between fields, so no further padding is added
  here.

  Note that the third field, VIGDAT, actually contains two 12-byte integer
  subfields.  No distinction is made in the program for this.
*/


main(argc,argv)
  int     argc;
  char   *argv[];

{ int             i,j,k,m;               /* loop/subscript variables */
  int             x[MAX_FIELDS];         /* fields to be extracted   */
  int             xfields;               /* number of x[] elements   */
  char           *rem;                   /* string pointer           */
  long int        number;                /* temporary holding place  */
  FILE           *ifp;                   /* input file pointer       */
  char            line[RECORD_LENGTH];   /* input buffer             */
  int             print_headers;         /* logical flag             */


  if (argc == 1)   /* No fields were listed */
    { fprintf (stderr,"Usage: extraj [-h] [field1] ... [fieldn-fieldm] ...\n");
      exit(0);
    }


  /*========================================================================*/

  /* Process the list of fields supplied on the command line: */

  i = 1;        /* i is used to reference the argument array */
  k = 0;        /* k is used to reference the x[] array      */

  /* Check for the "-h" switch, which must be the first argument if it appears:
  */

  if (strcmp(argv[1],"-h") == 0)
    { print_headers = 1;
      i = 2;
    }
  else
    { print_headers = 0; }

  /* The rest of the arguments: */

  while (i<argc)
    { 
      /* Attempt to convert the argument to a single integer.  If successful,
         save that integer in the 'x' array:
      */

      number = strtol(argv[i], &rem, 10);

      /* Verify the number.  If it is invalid, discard it, otherwise, save
         it in the next x[] element and increment k: 
      */

      if (number < 1  ||  number > 114)
        { fprintf (stderr,"extraj: Invalid field number (%s), ignored.\n",
                           argv[i]);
          ++i;
          continue;    /* Go directly to next argument in list */
        }
      else
        { x[k++] = number; 
          if (k>=MAX_FIELDS)
            { fprintf (stderr,"extraj: Maximum number of fields (%d) ",
                              MAX_FIELDS);
              fprintf (stderr,"exceeded.\n");
            }
        }

      /* Check for a range specification and add all the intervening
         fields to the list.

         Range specifications must be of the form "A-B", where A<=B and
         there is no intervening white space.

         A range may exist of the previous conversion had an unconverted
         remainder, the first character of which is a hyphen (-).  Any
         other non-empty remainder from the conversion is an error.
      */

      if ((strcmp(rem,"") != 0)  &&  (rem[0] == '-'))
        { 
          /* Attempt to convert the remainder after the hyphen to an integer.
             Any more remainder after this conversion is an error.  In case
             of error, the entire range is discarded, including the first
             (valid) number.
          */

          number = strtol(rem+1, &rem, 10);
          if (number < 1       ||  number > 114 ||
              number < x[k-1]  ||  strcmp(rem,"") != 0)
            { fprintf (stderr, "extraj: Invalid range (%s), ignored.\n",
                                argv[i]);
              k--;  
            }
          else
            { 
              /* Both end points of the range are valid.  This loop fills
                 in the intervening number by explicitly listing them in
                 the x[] array:
              */
              m = k-1;
              for (j=x[m]+1; j<=number; ++j)
                { x[k++] = j; 
                  if (k>=MAX_FIELDS)
                    { fprintf (stderr,"extraj: Maximum number of fields (%d) ",
                                      MAX_FIELDS);
                      fprintf (stderr,"exceeded.\n");
                    }
                }
            }
        }

      else if (strcmp(rem,"") != 0)
        { fprintf (stderr, "extraj: Invalid field (%s) ignored.\n",
                            argv[i]);
          k--;
        }

      ++i;   /* Next field */
    }

  /* Save the number of fields to be extracted.  Make sure it is >0: */

  xfields = k;    

  if (xfields < 1)
    { fprintf (stderr,"extraj: No fields to extract.\n");
      exit(10);
    }


  /*========================================================================*/
  
  /* Open the input file: */

  if ((ifp=fopen(EPHEMERIS_FILE,"r")) == NULL)
    { fprintf (stderr,"extraj: Unable to open input file \"%s\" (%s).\n",
                       EPHEMERIS_FILE, strerror(errno));
      exit(1);
    }

  /* Read the first line, which just contains variable labels (although
     it is the same size as all other records in the file).  If the "-h"
     switch was included on the command line, then print the field labels
     to the output file as well.

     Note that the labels are in a uniform format of 114(2X,A6).  This
     code centers each label over its respective column in the output file.
  */

  fread ((void *)line, 1, RECORD_LENGTH, ifp);
  if (print_headers)
    { for (i=0; i<xfields; ++i)
        { m = x[i] - 1;
          fprintf (stdout,"         ");
          fprintf (stdout,"%6.6s",line+(m*8)+2);
          fprintf (stdout,"         ");
        }
      fprintf(stdout,"\r\n");
    }


  /* Loop through the file records, extracting and outputting the requested
     fields for each record:
  */

  i = 0;   /* i is used to count file data records. */

  while (fread((void *)line, 1, RECORD_LENGTH, ifp) == RECORD_LENGTH)
    { ++i;
      for (j=0; j<xfields; ++j)
        { m = x[j] - 1;                  /* m is the 0-based field number */
          fprintf (stdout,"%24.24s",line+(m*24)); 
        }
      fprintf (stdout,"\r\n");
    }


  /*========================================================================*/

  fclose(ifp);
  exit(0);
}
