/******************************************************************/
/* Program -MVMASM- Assembly language parser for MVS assembly     */
/* language.  To be used as a parser in TeamConnection.           */
/* Written by KM - 10/10/97                                       */
/******************************************************************/
/* 5696-737 (C) COPYRIGHT IBM CORP. 1988-97                       */
/* LICENSED MATERIAL - PROGRAM PROPERTY OF IBM                    */
/******************************************************************/


#if defined(__NT__)
#include <io.h>
#endif

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <ctype.h>
#include "mvsasmp.h"


/**************************************/
/* Global variables                   */
/**************************************/
int  NumSurpluswords = 0;
char Infilename[80], Outfilename[80];
FILE *Infile, *Outfile;
/**************************************/


/* Retrieves parameter */
void getparam(int argc, char **argv, char *infilename, char *outfilename)
{
   /* Get parameter */
   if (argc-1 == 0)
   {
      printf("\nInvalid number of parameters\n");
      printf("Syntax: MVSASMP  <input file>  [output file]\n\n");
      exit(1);
   }
   else
   {
      strcpy(infilename, argv[1]);
      if (argc-1 >= 2)
         strcpy(outfilename, argv[2]);
      else
         strcpy(outfilename, OUTFILE);
   }
}


/* Opens input and output files */
FILE *openfile(char *filename, char *mode)
{
   FILE *file;

   if (!(file = fopen(filename, mode)))
   {
      printf("\nError opening %s file\n", mode[0]=='r' ? "ASM source input" : "output");
      exit(1);
   }

   return file;
}


/* Loads the MVS surplus keywords from file if file exists */
void loadsurpluswords()
{
   char line[MAX_LINELENGTH+1], word[MAX_WORDLENGTH+1];
   FILE *file;

   if ((file = fopen(SURPLUSFILE, "r")))
   {
      while (fgets(line, sizeof(line), file))
      {
         /* Remove linefeed character at end of string */
         if (line[0] && line[strlen(line)-1] == '\n')
            line[strlen(line)-1] = 0;

         /* Add word to list */
         if (sscanf(line, "%s", word) == 1)
            if (NumSurpluswords < MAX_SURPLUSWORDS)
            {
               if ((SurplusWords[NumSurpluswords] = malloc(strlen(word)+1)) == NULL)
               {
                  printf("\nError: Insufficient memory to load keywords from %s", SURPLUSFILE);
                  exit(1);
               }
               strcpy(SurplusWords[NumSurpluswords++], word);
            }
            else
            {
               printf("\nError: Maximum keywords of %d in %s has been exceeded\n", MAX_SURPLUSWORDS, SURPLUSFILE);
               exit(1);
            }
      }

      fclose(file);
   }
}


/* Performs binary search on keyword */
int isMVSWord(int top, int bottom, char **dbase, char *keyword)
{
   int middle;

   /* Check for terminating condition */
   if (top+1 == bottom)
      if (strcmp(keyword, dbase[top]) != 0 &&
          strcmp(keyword, dbase[bottom]) != 0)
         return 0;
      else
         return 1;

   /* Use binary sort to find keyword */
   middle = (top + bottom) / 2;
   if (strcmp(keyword, dbase[middle]) == 0)
      return 1;
   if (strcmp(keyword, dbase[middle]) < 0)
      return isMVSWord(top, middle, dbase, keyword);
   else
      return isMVSWord(middle, bottom, dbase, keyword);
}


/* Determines if the keyword is an MVS */
/* keyword using a binary sort algorithm. */
/* Returns 1 if true and 0 otherwise */
int isMVSKeyword(char *keyword)
{
   int pos;

   /* Check standard keywords, then check surplsu file */
   if (!isMVSWord(0, NUM_KEYWORDS-1, Keywords, keyword))
   {
      for (pos = 0; pos < NumSurpluswords; pos++)
         if (strcmp(keyword, SurplusWords[pos]) == 0)
            return 1;
   }
   else
      return 1;

   return 0;
}


/**************************************************************/
/* Parses the ASM file for COPY statements:                   */
/**************************************************************/
/*  If first col = '*', the line is a comment.                */
/*  All COPY statements will begin on column 10.              */
/*  If COPY statement is ommited, parser will search database */
/*  of MVS keywords for word.  If no match is found, the      */
/*  word found in place of the COPY statement will be added   */
/*  to the list of include files for the build.               */
/**************************************************************/
void parsefile(FILE *infile, FILE *outfile)
{
   char line[MAX_LINELENGTH+1],
        copyname[MAX_FILENAMELEN+1];

   while (fgets(line, sizeof(line), infile))
   {
      /* Remove linefeed character at end of string */
      if (line[0] && line[strlen(line)-1] == '\n')
         line[strlen(line)-1] = 0;

      /* Append spaces to the line */
      while (strlen(line) < MAX_LINELENGTH)
         strcat(line, " ");

      /* Skip comments */
      if (line[0] != KEYWORD_COMMENT[0])
      {
         /* Check for 'COPY' statement and extract next parameter.    */
         /* If not found, determine if keyword refers to an           */
         /* include file by searching for it in MVS keyword database. */
         /* If keyword is NOT an MVS keyword, then it refers          */
         /* to an include file.                                       */
         if (strstr(&line[COPYCOLUMN], KEYWORD_COPY) == &line[COPYCOLUMN] &&
             sscanf(&line[COPYCOLUMN+strlen(KEYWORD_COPY)], "%s", copyname) == 1)
            fprintf(outfile, "%s\n", copyname);
         else
            if (sscanf(&line[COPYCOLUMN], "%s", copyname) == 1 &&
                !isspace(line[COPYCOLUMN]) &&
                !isMVSKeyword(copyname))
               fprintf(outfile, "%s\n", copyname);
      }
   }
}



/**************************************/
/* Main Program                       */
/**************************************/
int main(int argc, char **argv)
{
   /* Get parameter */
   getparam(argc, argv, Infilename, Outfilename);

   /* Open files */
   if ((Infile = openfile(Infilename, "r")))
      Outfile = openfile(Outfilename, "w");

   /* Read MVS surplus keyword database */
   loadsurpluswords();

   /* Parse input file */
   parsefile(Infile, Outfile);

   /* Close files */
   fclose(Infile);
   fclose(Outfile);

   return 0;
}
